diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 1ceedf460550340da2270d8cb9719ab38b3fb466..3e3af6ede30e5411ddabdaa1d8c62447aba1e7e9 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -496,6 +496,7 @@ public:
         AA_UseSoftwareOpenGL = 17,
         AA_ShareOpenGLContexts = 18,
         AA_SetPalette = 19,
+        AA_NoHighDpiScaling = 20,
 
         // Add new attributes before this line
         AA_AttributeCount
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index c5617c1616fff4d5b2125673c2120815492b0e41..aeff9502feb969706deee46931f03012df89fa91 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -197,6 +197,11 @@
     \value AA_SetPalette Indicates whether a palette was explicitly set on the
            QApplication/QGuiApplication. This value has been added in Qt 5.5.
 
+    \value AA_NoHighDpiScaling Disables all high-DPI scaling in Qt, exposing window
+           system coordinates. Note that the window system may do its own scaling,
+           so this does not guarantee that QPaintDevice::devicePixelRatio() will
+           be equal to 1. This value has been added in Qt 5.6.
+
     The following values are obsolete:
 
     \value AA_ImmediateWidgetCreation This attribute is no longer fully
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index af6a41760808c42a73265a3dd939aeb7b1e4cb20..73a5a7b6ab243a67734b7d03063908b9d1ed478f 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -75,7 +75,9 @@ HEADERS += \
         kernel/qplatformgraphicsbuffer.h \
         kernel/qplatformgraphicsbufferhelper.h \
         kernel/qinputdevicemanager_p.h \
-        kernel/qinputdevicemanager_p_p.h
+        kernel/qinputdevicemanager_p_p.h \
+        kernel/qhighdpiscaling_p.h
+
 
 SOURCES += \
         kernel/qgenericpluginfactory.cpp \
@@ -131,7 +133,9 @@ SOURCES += \
         kernel/qrasterwindow.cpp \
         kernel/qplatformgraphicsbuffer.cpp \
         kernel/qplatformgraphicsbufferhelper.cpp \
-        kernel/qinputdevicemanager.cpp
+        kernel/qinputdevicemanager.cpp \
+        kernel/qhighdpiscaling.cpp
+
 
 contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles2) {
     HEADERS += \
diff --git a/src/gui/kernel/qcursor.cpp b/src/gui/kernel/qcursor.cpp
index 6ed750eda12215b2150f9d586ba0d5d5ad9c22b4..dbf2b3c21ff5348c34975d1edf5df92a72d5b82b 100644
--- a/src/gui/kernel/qcursor.cpp
+++ b/src/gui/kernel/qcursor.cpp
@@ -43,6 +43,7 @@
 
 #include <qpa/qplatformcursor.h>
 #include <private/qguiapplication_p.h>
+#include <private/qhighdpiscaling_p.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -177,9 +178,14 @@ QT_BEGIN_NAMESPACE
 */
 QPoint QCursor::pos(const QScreen *screen)
 {
-    if (screen)
-        if (const QPlatformCursor *cursor = screen->handle()->cursor())
-            return cursor->pos();
+    if (screen) {
+        if (const QPlatformCursor *cursor = screen->handle()->cursor()) {
+            const QPlatformScreen *ps = screen->handle();
+            QPoint nativePos = cursor->pos();
+            ps = ps->screenForPosition(nativePos);
+            return QHighDpi::fromNativePixels(nativePos, ps->screen());
+        }
+    }
     return QGuiApplicationPrivate::lastCursorPosition.toPoint();
 }
 
@@ -231,12 +237,12 @@ void QCursor::setPos(QScreen *screen, int x, int y)
 {
     if (screen) {
         if (QPlatformCursor *cursor = screen->handle()->cursor()) {
-            const QPoint pos = QPoint(x, y);
+            const QPoint devicePos = QHighDpi::toNativePixels(QPoint(x, y), screen);
             // Need to check, since some X servers generate null mouse move
             // events, causing looping in applications which call setPos() on
             // every mouse move event.
-            if (pos != cursor->pos())
-                cursor->setPos(pos);
+            if (devicePos != cursor->pos())
+                cursor->setPos(devicePos);
         }
     }
 }
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 2a451453d07bcbefaa64f904050ef7817899c448..00b0c464dfc7dae5da53407eede6505deb08e46a 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -959,8 +959,10 @@ QWindow *QGuiApplication::topLevelAt(const QPoint &pos)
     QList<QScreen *>::const_iterator end = screens.constEnd();
 
     while (screen != end) {
-        if ((*screen)->geometry().contains(pos))
-            return (*screen)->handle()->topLevelAt(pos);
+        if ((*screen)->geometry().contains(pos)) {
+            const QPoint devicePosition = QHighDpi::toNativePixels(pos, *screen);
+            return (*screen)->handle()->topLevelAt(devicePosition);
+        }
         ++screen;
     }
     return 0;
@@ -1116,6 +1118,9 @@ void QGuiApplicationPrivate::createPlatformIntegration()
     // this flag.
     QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true);
 
+
+    QHighDpiScaling::initHighDpiScaling();
+
     // Load the platform integration
     QString platformPluginPath = QLatin1String(qgetenv("QT_QPA_PLATFORM_PLUGIN_PATH"));
 
@@ -1178,6 +1183,8 @@ void QGuiApplicationPrivate::createPlatformIntegration()
 
     if (!icon.isEmpty())
         forcedWindowIcon = QDir::isAbsolutePath(icon) ? QIcon(icon) : QIcon::fromTheme(icon);
+
+    QHighDpiScaling::updateHighDpiScaling();
 }
 
 /*!
@@ -1822,7 +1829,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
         points << point;
 
         QEvent::Type type;
-        QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::convertTouchPoints(points, &type);
+        QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, &type);
 
         QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, m_fakeTouchDevice, touchPoints, e->modifiers);
         fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
@@ -2032,6 +2039,11 @@ void QGuiApplicationPrivate::processWindowScreenChangedEvent(QWindowSystemInterf
             window->d_func()->setTopLevelScreen(screen, false /* recreate */);
         else // Fall back to default behavior, and try to find some appropriate screen
             window->setScreen(0);
+        // we may have changed scaling, so trigger resize event if needed
+        if (window->handle()) {
+            QWindowSystemInterfacePrivate::GeometryChangeEvent gce(window, QHighDpi::fromNativePixels(window->handle()->geometry(), window), QRect());
+            processGeometryChangeEvent(&gce);
+        }
     }
 }
 
diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..19e3045fc95b3e64630f1bc1073736fed25c8284
--- /dev/null
+++ b/src/gui/kernel/qhighdpiscaling.cpp
@@ -0,0 +1,320 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtGui module 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhighdpiscaling_p.h"
+#include "qguiapplication.h"
+#include "qscreen.h"
+#include "qplatformintegration.h"
+#include "private/qscreen_p.h"
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcScaling, "qt.scaling");
+
+static const char legacyDevicePixelEnvVar[] = "QT_DEVICE_PIXEL_RATIO";
+static const char scaleFactorEnvVar[] = "QT_SCALE_FACTOR";
+static const char autoScreenEnvVar[] = "QT_AUTO_SCREEN_SCALE_FACTOR";
+static const char screenFactorsEnvVar[] = "QT_SCREEN_SCALE_FACTORS";
+
+static inline qreal initialScaleFactor()
+{
+
+    qreal result = 1;
+    if (qEnvironmentVariableIsSet(scaleFactorEnvVar)) {
+        bool ok;
+        const qreal f = qgetenv(scaleFactorEnvVar).toDouble(&ok);
+        if (ok && f > 0) {
+            qCDebug(lcScaling) << "Apply " << scaleFactorEnvVar << f;
+            result = f;
+        }
+    } else {
+        if (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar)) {
+            qWarning() << "Warning:" << legacyDevicePixelEnvVar << "is deprecated. Instead use:";
+            qWarning() << "   " << autoScreenEnvVar << "to enable platform plugin controlled per-screen factors.";
+            qWarning() << "   " << screenFactorsEnvVar << "to set per-screen factors.";
+            qWarning() << "   " << scaleFactorEnvVar << "to set the application global scale factor.";
+
+            int dpr = qEnvironmentVariableIntValue(legacyDevicePixelEnvVar);
+            if (dpr > 0)
+                result = dpr;
+        }
+    }
+    return result;
+}
+
+/*!
+    \class QHighDpiScaling
+    \since 5.6
+    \internal
+    \preliminary
+    \ingroup qpa
+
+    \brief Collection of utility functions for UI scaling.
+
+    QHighDpiScaling implements utility functions for high-dpi scaling for use
+    on operating systems that provide limited support for native scaling. In
+    addition this functionality can be used for simulation and testing purposes.
+
+    The functions support scaling between the device independent coordinate
+    system used by Qt applications and the native coordinate system used by
+    the platform plugins. Intended usage locations are the low level / platform
+    plugin interfacing parts of QtGui, for example the QWindow, QScreen and
+    QWindowSystemInterface implementation.
+
+    The coordinate system scaling is enabled by setting one or more scale
+    factors. These will then be factored into the value returned by the
+    devicePixelRatio() accessors (any native scale factor will also be
+    included in this value). Several setters are available:
+
+    - A process-global scale factor
+        - QT_SCALE_FACTOR (environment variable)
+        - QHighDpiScaling::setGlobalFactor()
+
+    - A per-screen scale factor
+        - QT_AUTO_SCALE_FACTOR (environment variable)
+          Setting this to a true-ish value will make QHighDpiScaling
+          call QPlatformScreen::pixelDensity()
+        - QHighDpiScaling::setScreenFactor(screen, factor);
+        - QT_SCREEN_SCALE_FACTORS (environment variable)
+        Set this to a semicolon-separated list of scale factors
+        (matching the order of QGuiApplications::screens()),
+        or to a list of name=value pairs (where name matches
+        QScreen::name()).
+
+    All scale factors are of type qreal.
+
+    The main scaling functions for use in QtGui are:
+        T toNativePixels(T, QWindow *)
+        T fromNativePixels(T, QWindow*)
+    Where T is QPoint, QSize, QRect etc.
+*/
+
+qreal QHighDpiScaling::m_factor = 1.0;
+bool QHighDpiScaling::m_active = false; //"overall active" - is there any scale factor set.
+bool QHighDpiScaling::m_usePixelDensity = false; // use scale factor from platform plugin
+bool QHighDpiScaling::m_pixelDensityScalingActive = false; // pixel density scale factor > 1
+bool QHighDpiScaling::m_globalScalingActive = false; // global scale factor is active
+bool QHighDpiScaling::m_screenFactorSet = false; // QHighDpiScaling::setScreenFactor has been used
+QDpi QHighDpiScaling::m_logicalDpi = QDpi(-1,-1); // The scaled logical DPI of the primary screen
+
+/*
+    Initializes the QHighDpiScaling global variables. Called before the
+    platform plugin is created.
+*/
+void QHighDpiScaling::initHighDpiScaling()
+{
+    if (QCoreApplication::testAttribute(Qt::AA_NoHighDpiScaling)) {
+        m_factor = 1;
+        m_active = false;
+        return;
+    }
+    m_factor = initialScaleFactor();
+    bool usePlatformPluginPixelDensity = qEnvironmentVariableIsSet(autoScreenEnvVar)
+                                         || qgetenv(legacyDevicePixelEnvVar).toLower() == "auto";
+
+    m_globalScalingActive = !qFuzzyCompare(m_factor, qreal(1));
+    m_usePixelDensity = usePlatformPluginPixelDensity;
+    m_pixelDensityScalingActive = false; //set in updateHighDpiScaling below
+
+    // we update m_active in updateHighDpiScaling, but while we create the
+    // screens, we have to assume that m_usePixelDensity implies scaling
+    m_active = m_globalScalingActive || m_usePixelDensity;
+}
+
+void QHighDpiScaling::updateHighDpiScaling()
+{
+    if (QCoreApplication::testAttribute(Qt::AA_NoHighDpiScaling))
+        return;
+
+    if (m_usePixelDensity && !m_pixelDensityScalingActive) {
+        Q_FOREACH (QScreen *screen, QGuiApplication::screens()) {
+            if (!qFuzzyCompare(screenSubfactor(screen->handle()), qreal(1))) {
+                m_pixelDensityScalingActive = true;
+                break;
+            }
+        }
+    }
+    if (qEnvironmentVariableIsSet(screenFactorsEnvVar)) {
+        int i = 0;
+        Q_FOREACH (const QByteArray &spec, qgetenv(screenFactorsEnvVar).split(';')) {
+            QScreen *screen = 0;
+            int equalsPos = spec.lastIndexOf('=');
+            double factor = 0;
+            if (equalsPos > 0) {
+                // support "name=factor"
+                QByteArray name = spec.mid(0, equalsPos);
+                QByteArray f = spec.mid(equalsPos + 1);
+                bool ok;
+                factor = f.toDouble(&ok);
+                if (ok) {
+                    Q_FOREACH (QScreen *s, QGuiApplication::screens()) {
+                        if (s->name() == QString::fromLocal8Bit(name)) {
+                            screen = s;
+                            break;
+                        }
+                    }
+                }
+            } else {
+                // listing screens in order
+                bool ok;
+                factor = spec.toDouble(&ok);
+                if (ok && i < QGuiApplication::screens().count())
+                    screen = QGuiApplication::screens().at(i);
+            }
+            if (screen)
+                setScreenFactor(screen, factor);
+            ++i;
+        }
+    }
+    m_active = m_globalScalingActive || m_screenFactorSet || m_pixelDensityScalingActive;
+
+    QPlatformScreen *primaryScreen = QGuiApplication::primaryScreen()->handle();
+    qreal sf = screenSubfactor(primaryScreen);
+    QDpi primaryDpi = primaryScreen->logicalDpi();
+    m_logicalDpi = QDpi(primaryDpi.first / sf, primaryDpi.second / sf);
+}
+
+/*
+    Sets the global scale factor which is applied to all windows.
+*/
+void QHighDpiScaling::setGlobalFactor(qreal factor)
+{
+    if (qFuzzyCompare(factor, m_factor))
+        return;
+    if (!QGuiApplication::allWindows().isEmpty())
+        qWarning() << Q_FUNC_INFO << "QHighDpiScaling::setFactor: Should only be called when no windows exist.";
+
+    m_globalScalingActive = !qFuzzyCompare(factor, qreal(1));
+    m_factor = m_globalScalingActive ? factor : qreal(1);
+    m_active = m_globalScalingActive || m_screenFactorSet || m_pixelDensityScalingActive;
+    Q_FOREACH (QScreen *screen, QGuiApplication::screens())
+         screen->d_func()->updateHighDpi();
+}
+
+static const char scaleFactorProperty[] = "_q_scaleFactor";
+
+/*
+    Sets a per-screen scale factor.
+*/
+void QHighDpiScaling::setScreenFactor(QScreen *screen, qreal factor)
+{
+    m_screenFactorSet = true;
+    m_active = true;
+    screen->setProperty(scaleFactorProperty, QVariant(factor));
+
+    // hack to force re-evaluation of screen geometry
+    if (screen->handle())
+        screen->d_func()->setPlatformScreen(screen->handle()); // updates geometries based on scale factor
+}
+
+QPoint QHighDpiScaling::mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen)
+{
+    if (!platformScreen)
+        return pos;
+    const qreal scaleFactor = factor(platformScreen);
+    const QPoint topLeft = platformScreen->geometry().topLeft();
+    return (pos - topLeft) * scaleFactor + topLeft;
+}
+
+QPoint QHighDpiScaling::mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen)
+{
+    if (!platformScreen)
+        return pos;
+    const qreal scaleFactor = factor(platformScreen);
+    const QPoint topLeft = platformScreen->geometry().topLeft();
+    return (pos - topLeft) / scaleFactor + topLeft;
+}
+
+qreal QHighDpiScaling::screenSubfactor(const QPlatformScreen *screen)
+{
+    qreal factor = qreal(1.0);
+    if (screen) {
+        if (m_usePixelDensity)
+            factor *= screen->pixelDensity();
+        if (m_screenFactorSet) {
+            QVariant screenFactor = screen->screen()->property(scaleFactorProperty);
+            if (screenFactor.isValid())
+                factor *= screenFactor.toReal();
+        }
+    }
+    return factor;
+}
+
+QDpi QHighDpiScaling::logicalDpi()
+{
+    return m_logicalDpi;
+}
+
+qreal QHighDpiScaling::factor(const QScreen *screen)
+{
+    // Fast path for when scaling in Qt is not used at all.
+    if (!m_active)
+        return qreal(1.0);
+
+    // The effective factor for a given screen is the product of the
+    // screen and global sub-factors
+    qreal factor = m_factor;
+    if (screen)
+        factor *= screenSubfactor(screen->handle());
+    return factor;
+}
+
+qreal QHighDpiScaling::factor(const QPlatformScreen *platformScreen)
+{
+    if (!m_active)
+        return qreal(1.0);
+
+    return m_factor * screenSubfactor(platformScreen);
+}
+
+qreal QHighDpiScaling::factor(const QWindow *window)
+{
+    if (!m_active)
+        return qreal(1.0);
+
+    return factor(window ? window->screen() : QGuiApplication::primaryScreen());
+}
+
+QPoint QHighDpiScaling::origin(const QScreen *screen)
+{
+    return screen->geometry().topLeft();
+}
+
+QPoint QHighDpiScaling::origin(const QPlatformScreen *platformScreen)
+{
+    return platformScreen->geometry().topLeft();
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h
new file mode 100644
index 0000000000000000000000000000000000000000..c79540d9e477c4753ae713b6e4ecc5b7ce02779d
--- /dev/null
+++ b/src/gui/kernel/qhighdpiscaling_p.h
@@ -0,0 +1,470 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtGui module 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHIGHDPISCALING_P_H
+#define QHIGHDPISCALING_P_H
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the Qt API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qmargins.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtGui/qregion.h>
+#include <QtGui/qscreen.h>
+#include <QtGui/qwindow.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcScaling);
+
+class QScreen;
+class QPlatformScreen;
+typedef QPair<qreal, qreal> QDpi;
+
+class Q_GUI_EXPORT QHighDpiScaling {
+public:
+    static void initHighDpiScaling();
+    static void updateHighDpiScaling();
+    static void setGlobalFactor(qreal factor);
+    static void setScreenFactor(QScreen *window, qreal factor);
+
+    static bool isActive() { return m_active; }
+    static qreal factor(const QWindow *window);
+    static qreal factor(const QScreen *screen);
+    static qreal factor(const QPlatformScreen *platformScreen);
+    static QPoint origin(const QScreen *screen);
+    static QPoint origin(const QPlatformScreen *platformScreen);
+    static QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen);
+    static QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen);
+    static QDpi logicalDpi();
+
+private:
+    static qreal screenSubfactor(const QPlatformScreen *screen);
+
+    static qreal m_factor;
+    static bool m_active;
+    static bool m_usePixelDensity;
+    static bool m_globalScalingActive;
+    static bool m_pixelDensityScalingActive;
+    static bool m_screenFactorSet;
+    static QDpi m_logicalDpi;
+};
+
+// Coordinate system conversion functions:
+// QHighDpi::fromNativePixels   : from physical(screen/backing) to logical pixels
+// QHighDpi::toNativePixels              : from logical to physical pixels
+
+namespace QHighDpi {
+
+inline QPointF fromNative(const QPointF &pos, qreal scaleFactor, const QPointF &origin)
+{
+     return (pos - origin) / scaleFactor + origin;
+}
+
+inline QPointF toNative(const QPointF &pos, qreal scaleFactor, const QPointF &origin)
+{
+     return (pos - origin) * scaleFactor + origin;
+}
+
+inline QPoint fromNative(const QPoint &pos, qreal scaleFactor, const QPoint &origin)
+{
+     return (pos - origin) / scaleFactor + origin;
+}
+
+inline QPoint toNative(const QPoint &pos, qreal scaleFactor, const QPoint &origin)
+{
+     return (pos - origin) * scaleFactor + origin;
+}
+
+inline QPoint fromNative(const QPoint &pos, qreal scaleFactor)
+{
+     return pos / scaleFactor;
+}
+
+inline QPoint toNative(const QPoint &pos, qreal scaleFactor)
+{
+    return pos * scaleFactor;
+}
+
+inline QSize fromNative(const QSize &size, qreal scaleFactor)
+{
+    return size / scaleFactor; // TODO: should we round up?
+}
+
+inline QSize toNative(const QSize &size, qreal scaleFactor)
+{
+    return size * scaleFactor;
+}
+
+inline QSizeF fromNative(const QSizeF &size, qreal scaleFactor)
+{
+    return size / scaleFactor;
+}
+
+inline QSizeF toNative(const QSizeF &size, qreal scaleFactor)
+{
+    return size * scaleFactor;
+}
+
+inline QRect fromNative(const QRect &rect, qreal scaleFactor, const QPoint &origin)
+{
+    return QRect(fromNative(rect.topLeft(), scaleFactor, origin), fromNative(rect.size(), scaleFactor));
+}
+
+inline QRect toNative(const QRect &rect, qreal scaleFactor, const QPoint &origin)
+{
+    return QRect(toNative(rect.topLeft(), scaleFactor, origin), toNative(rect.size(), scaleFactor));
+
+}
+
+inline QRect fromNative(const QRect &rect, const QScreen *screen, const QPoint &screenOrigin)
+{
+    return toNative(rect, QHighDpiScaling::factor(screen), screenOrigin);
+}
+
+inline QRect fromNativeScreenGeometry(const QRect &nativeScreenGeometry, const QScreen *screen)
+{
+    return QRect(nativeScreenGeometry.topLeft(),
+                 fromNative(nativeScreenGeometry.size(), QHighDpiScaling::factor(screen)));
+}
+
+inline QPoint fromNativeLocalPosition(const QPoint &pos, const QWindow *window)
+{
+    const qreal scaleFactor = QHighDpiScaling::factor(window);
+    return pos / scaleFactor;
+}
+
+inline QPoint toNativeLocalPosition(const QPoint &pos, const QWindow *window)
+{
+    const qreal scaleFactor = QHighDpiScaling::factor(window);
+    return pos * scaleFactor;
+}
+
+inline QPointF fromNativeLocalPosition(const QPointF &pos, const QWindow *window)
+{
+    const qreal scaleFactor = QHighDpiScaling::factor(window);
+    return pos / scaleFactor;
+}
+
+inline QPointF toNativeLocalPosition(const QPointF &pos, const QWindow *window)
+{
+    const qreal scaleFactor = QHighDpiScaling::factor(window);
+    return pos * scaleFactor;
+}
+
+inline QRect fromNativePixels(const QRect &pixelRect, const QPlatformScreen *platformScreen)
+{
+    const qreal scaleFactor = QHighDpiScaling::factor(platformScreen);
+    const QPoint origin = QHighDpiScaling::origin(platformScreen);
+    return QRect(fromNative(pixelRect.topLeft(), scaleFactor, origin),
+                 fromNative(pixelRect.size(), scaleFactor));
+}
+
+inline QRect toNativePixels(const QRect &pointRect, const QPlatformScreen *platformScreen)
+{
+    const qreal scaleFactor = QHighDpiScaling::factor(platformScreen);
+    const QPoint origin = QHighDpiScaling::origin(platformScreen);
+    return QRect(toNative(pointRect.topLeft(), scaleFactor, origin),
+                 toNative(pointRect.size(), scaleFactor));
+}
+
+inline QRect fromNativePixels(const QRect &pixelRect, const QScreen *screen)
+{
+    const qreal scaleFactor = QHighDpiScaling::factor(screen);
+    const QPoint origin = QHighDpiScaling::origin(screen);
+    return QRect(fromNative(pixelRect.topLeft(), scaleFactor, origin),
+                 fromNative(pixelRect.size(), scaleFactor));
+}
+
+inline QRect toNativePixels(const QRect &pointRect, const QScreen *screen)
+{
+    const qreal scaleFactor = QHighDpiScaling::factor(screen);
+    const QPoint origin = QHighDpiScaling::origin(screen);
+    return QRect(toNative(pointRect.topLeft(), scaleFactor, origin),
+                 toNative(pointRect.size(), scaleFactor));
+}
+
+inline QRect fromNativePixels(const QRect &pixelRect, const QWindow *window)
+{
+    if (window && window->isTopLevel() && window->screen()) {
+        return fromNativePixels(pixelRect, window->screen());
+    } else {
+        const qreal scaleFactor = QHighDpiScaling::factor(window);
+        return QRect(pixelRect.topLeft() / scaleFactor, fromNative(pixelRect.size(), scaleFactor));
+    }
+}
+
+inline QRectF toNativePixels(const QRectF &pointRect, const QScreen *screen)
+{
+    const qreal scaleFactor = QHighDpiScaling::factor(screen);
+    const QPoint origin = QHighDpiScaling::origin(screen);
+    return QRectF(toNative(pointRect.topLeft(), scaleFactor, origin),
+                 toNative(pointRect.size(), scaleFactor));
+}
+
+inline QRect toNativePixels(const QRect &pointRect, const QWindow *window)
+{
+    if (window && window->isTopLevel() && window->screen()) {
+        return toNativePixels(pointRect, window->screen());
+    } else {
+        const qreal scaleFactor = QHighDpiScaling::factor(window);
+        return QRect(pointRect.topLeft() * scaleFactor, toNative(pointRect.size(), scaleFactor));
+    }
+}
+
+inline QRectF fromNativePixels(const QRectF &pixelRect, const QScreen *screen)
+{
+    const qreal scaleFactor = QHighDpiScaling::factor(screen);
+    const QPoint origin = QHighDpiScaling::origin(screen);
+    return QRectF(fromNative(pixelRect.topLeft(), scaleFactor, origin),
+                 fromNative(pixelRect.size(), scaleFactor));
+}
+
+inline QRectF fromNativePixels(const QRectF &pixelRect, const QWindow *window)
+{
+    if (window && window->isTopLevel() && window->screen()) {
+        return fromNativePixels(pixelRect, window->screen());
+    } else {
+        const qreal scaleFactor = QHighDpiScaling::factor(window);
+        return QRectF(pixelRect.topLeft() / scaleFactor, pixelRect.size() / scaleFactor);
+    }
+}
+
+inline QRectF toNativePixels(const QRectF &pointRect, const QWindow *window)
+{
+    if (window && window->isTopLevel() && window->screen()) {
+        return toNativePixels(pointRect, window->screen());
+    } else {
+        const qreal scaleFactor = QHighDpiScaling::factor(window);
+        return QRectF(pointRect.topLeft() * scaleFactor, pointRect.size() * scaleFactor);
+    }
+}
+
+inline QSize fromNativePixels(const QSize &pixelSize, const QWindow *window)
+{
+    return pixelSize / QHighDpiScaling::factor(window);
+}
+
+inline QSize toNativePixels(const QSize &pointSize, const QWindow *window)
+{
+    return pointSize * QHighDpiScaling::factor(window);
+}
+
+inline QSizeF fromNativePixels(const QSizeF &pixelSize, const QWindow *window)
+{
+    return pixelSize / QHighDpiScaling::factor(window);
+}
+
+inline QSizeF toNativePixels(const QSizeF &pointSize, const QWindow *window)
+{
+    return pointSize * QHighDpiScaling::factor(window);
+}
+
+inline QPoint fromNativePixels(const QPoint &pixelPoint, const QScreen *screen)
+{
+    return fromNative(pixelPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen));
+}
+
+inline QPoint fromNativePixels(const QPoint &pixelPoint, const QWindow *window)
+{
+    if (window && window->isTopLevel() && window->screen())
+        return fromNativePixels(pixelPoint, window->screen());
+    else
+        return pixelPoint / QHighDpiScaling::factor(window);
+}
+
+inline QPoint toNativePixels(const QPoint &pointPoint, const QScreen *screen)
+{
+    return toNative(pointPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen));
+}
+
+inline QPoint toNativePixels(const QPoint &pointPoint, const QWindow *window)
+{
+    if (window && window->isTopLevel() && window->screen())
+        return toNativePixels(pointPoint, window->screen());
+    else
+        return pointPoint * QHighDpiScaling::factor(window);
+}
+
+inline QPointF fromNativePixels(const QPointF &pixelPoint, const QScreen *screen)
+{
+    return fromNative(pixelPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen));
+}
+
+inline QPointF fromNativePixels(const QPointF &pixelPoint, const QWindow *window)
+{
+    if (window && window->isTopLevel() && window->screen())
+        return fromNativePixels(pixelPoint, window->screen());
+    else
+        return pixelPoint / QHighDpiScaling::factor(window);
+}
+
+inline QPointF toNativePixels(const QPointF &pointPoint, const QScreen *screen)
+{
+    return toNative(pointPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen));
+}
+
+inline QPointF toNativePixels(const QPointF &pointPoint, const QWindow *window)
+{
+     if (window && window->isTopLevel() && window->screen())
+        return toNativePixels(pointPoint, window->screen());
+    else
+        return pointPoint * QHighDpiScaling::factor(window);
+}
+
+inline QMargins fromNativePixels(const QMargins &pixelMargins, const QWindow *window)
+{
+    const qreal scaleFactor = QHighDpiScaling::factor(window);
+    return QMargins(pixelMargins.left() / scaleFactor, pixelMargins.top() / scaleFactor,
+                    pixelMargins.right() / scaleFactor, pixelMargins.bottom() / scaleFactor);
+}
+
+inline QMargins toNativePixels(const QMargins &pointMargins, const QWindow *window)
+{
+    const qreal scaleFactor = QHighDpiScaling::factor(window);
+    return QMargins(pointMargins.left() * scaleFactor, pointMargins.top() * scaleFactor,
+                    pointMargins.right() * scaleFactor, pointMargins.bottom() * scaleFactor);
+}
+
+inline QRegion fromNativeLocalRegion(const QRegion &pixelRegion, const QWindow *window)
+{
+    if (!QHighDpiScaling::isActive())
+        return pixelRegion;
+
+    qreal scaleFactor = QHighDpiScaling::factor(window);
+    QRegion pointRegion;
+    foreach (const QRect &rect, pixelRegion.rects()) {
+        pointRegion += QRect(fromNative(rect.topLeft(), scaleFactor),
+                             fromNative(rect.size(), scaleFactor));
+    }
+    return pointRegion;
+}
+
+inline QRegion toNativeLocalRegion(const QRegion &pointRegion, const QWindow *window)
+{
+    if (!QHighDpiScaling::isActive())
+        return pointRegion;
+
+    qreal scaleFactor = QHighDpiScaling::factor(window);
+    QRegion pixelRegon;
+    foreach (const QRect &rect, pointRegion.rects()) {
+        pixelRegon += QRect(toNative(rect.topLeft(), scaleFactor),
+                             toNative(rect.size(), scaleFactor));
+    }
+    return pixelRegon;
+}
+
+// Any T that has operator/()
+template <typename T>
+T fromNativePixels(const T &pixelValue, const QWindow *window)
+{
+    if (!QHighDpiScaling::isActive())
+        return pixelValue;
+
+    return pixelValue / QHighDpiScaling::factor(window);
+
+}
+
+    //##### ?????
+template <typename T>
+T fromNativePixels(const T &pixelValue, const QScreen *screen)
+{
+    if (!QHighDpiScaling::isActive())
+        return pixelValue;
+
+    return pixelValue / QHighDpiScaling::factor(screen);
+
+}
+
+// Any T that has operator*()
+template <typename T>
+T toNativePixels(const T &pointValue, const QWindow *window)
+{
+    if (!QHighDpiScaling::isActive())
+        return pointValue;
+
+    return pointValue * QHighDpiScaling::factor(window);
+}
+
+template <typename T>
+T toNativePixels(const T &pointValue, const QScreen *screen)
+{
+    if (!QHighDpiScaling::isActive())
+        return pointValue;
+
+    return pointValue * QHighDpiScaling::factor(screen);
+}
+
+
+// Any QVector<T> where T has operator/()
+template <typename T>
+QVector<T> fromNativePixels(const QVector<T> &pixelValues, const QWindow *window)
+{
+    if (!QHighDpiScaling::isActive())
+        return pixelValues;
+
+    QVector<T> pointValues;
+    foreach (const T& pixelValue, pixelValues)
+        pointValues.append(pixelValue / QHighDpiScaling::factor(window));
+    return pointValues;
+}
+
+// Any QVector<T> where T has operator*()
+template <typename T>
+QVector<T> toNativePixels(const QVector<T> &pointValues, const QWindow *window)
+{
+    if (!QHighDpiScaling::isActive())
+        return pointValues;
+
+    QVector<T> pixelValues;
+    foreach (const T& pointValue, pointValues)
+        pixelValues.append(pointValue * QHighDpiScaling::factor(window));
+    return pixelValues;
+}
+
+} // namespace QHighDpi
+
+QT_END_NAMESPACE
+
+#endif // QHIGHDPISCALING_P_H
diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp
index 4d973d47a5bd2f47d9928211977eda7f4a0c9463..e935907a62c5cef79262c1952ea7ad451f6113a7 100644
--- a/src/gui/kernel/qplatformintegration.cpp
+++ b/src/gui/kernel/qplatformintegration.cpp
@@ -39,7 +39,6 @@
 #include <qpa/qplatformtheme.h>
 #include <QtGui/private/qguiapplication_p.h>
 #include <QtGui/private/qpixmap_raster_p.h>
-#include <qpa/qplatformscreen_p.h>
 #include <private/qdnd_p.h>
 #include <private/qsimpledrag_p.h>
 
@@ -450,7 +449,7 @@ QList<int> QPlatformIntegration::possibleKeys(const QKeyEvent *) const
 void QPlatformIntegration::screenAdded(QPlatformScreen *ps, bool isPrimary)
 {
     QScreen *screen = new QScreen(ps);
-    ps->d_func()->screen = screen;
+
     if (isPrimary) {
         QGuiApplicationPrivate::screen_list.prepend(screen);
     } else {
@@ -469,8 +468,9 @@ void QPlatformIntegration::screenAdded(QPlatformScreen *ps, bool isPrimary)
 */
 void QPlatformIntegration::destroyScreen(QPlatformScreen *screen)
 {
-    QGuiApplicationPrivate::screen_list.removeOne(screen->d_func()->screen);
-    delete screen->d_func()->screen;
+    QScreen *qScreen = screen->screen();
+    QGuiApplicationPrivate::screen_list.removeOne(qScreen);
+    delete qScreen;
     delete screen;
 }
 
diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp
index 9aab102de34669f2497e69a604bb078728c944de..2fb53fe16bcbdc14362b983506b62d57c3fc14c6 100644
--- a/src/gui/kernel/qplatformscreen.cpp
+++ b/src/gui/kernel/qplatformscreen.cpp
@@ -40,6 +40,7 @@
 #include <qpa/qplatformintegration.h>
 #include <QtGui/qscreen.h>
 #include <QtGui/qwindow.h>
+#include <private/qhighdpiscaling_p.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -96,6 +97,23 @@ QWindow *QPlatformScreen::topLevelAt(const QPoint & pos) const
     return 0;
 }
 
+/*!
+  Find the sibling screen corresponding to \a globalPos.
+
+  Returns this screen if no suitable screen is found at the position.
+ */
+const QPlatformScreen *QPlatformScreen::screenForPosition(const QPoint &point) const
+{
+    if (!geometry().contains(point)) {
+        Q_FOREACH (const QPlatformScreen* screen, virtualSiblings()) {
+            if (screen->geometry().contains(point))
+                return screen;
+        }
+    }
+    return this;
+}
+
+
 /*!
     Returns a list of all the platform screens that are part of the same
     virtual desktop.
@@ -156,17 +174,37 @@ QDpi QPlatformScreen::logicalDpi() const
 }
 
 /*!
-    Reimplement this function in subclass to return the device pixel
-    ratio for the screen. This is the ratio between physical pixels
-    and device-independent pixels.
+    Reimplement this function in subclass to return the device pixel ratio
+    for the screen. This is the ratio between physical pixels and the
+    device-independent pixels of the windowing system. The default
+    implementation returns 1.0.
 
-    \sa QPlatformWindow::devicePixelRatio();
+    \sa QPlatformWindow::devicePixelRatio()
+    \sa QPlatformScreen::pixelDensity()
 */
 qreal QPlatformScreen::devicePixelRatio() const
 {
     return 1.0;
 }
 
+/*!
+    Reimplement this function in subclass to return the pixel density of the
+    screen. This is the scale factor needed to make a low-dpi application
+    usable on this screen. The default implementation returns 1.0.
+
+    Returning something else than 1.0 from this function causes Qt to
+    apply the scale factor to the application's coordinate system.
+    This is different from devicePixelRatio, which reports a scale
+    factor already applied by the windowing system. A platform plugin
+    typically implements one (or none) of these two functions.
+
+    \sa QPlatformWindow::devicePixelRatio()
+*/
+qreal QPlatformScreen::pixelDensity()  const
+{
+    return 1.0;
+}
+
 /*!
     Reimplement this function in subclass to return the vertical refresh rate
     of the screen, in Hz.
@@ -290,8 +328,8 @@ void QPlatformScreen::resizeMaximizedWindows()
     // 'screen()' still has the old geometry info while 'this' has the new geometry info
     const QRect oldGeometry = screen()->geometry();
     const QRect oldAvailableGeometry = screen()->availableGeometry();
-    const QRect newGeometry = geometry();
-    const QRect newAvailableGeometry = availableGeometry();
+    const QRect newGeometry = deviceIndependentGeometry();
+    const QRect newAvailableGeometry = QHighDpi::fromNative(availableGeometry(), QHighDpiScaling::factor(this), newGeometry.topLeft());
 
     // make sure maximized and fullscreen windows are updated
     for (int i = 0; i < windows.size(); ++i) {
@@ -393,6 +431,13 @@ QRect QPlatformScreen::mapBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation
     return rect;
 }
 
+QRect QPlatformScreen::deviceIndependentGeometry() const
+{
+    qreal scaleFactor = QHighDpiScaling::factor(this);
+    QRect nativeGeometry = geometry();
+    return QRect(nativeGeometry.topLeft(), QHighDpi::fromNative(nativeGeometry.size(), scaleFactor));
+}
+
 /*!
   Returns a hint about this screen's subpixel layout structure.
 
diff --git a/src/gui/kernel/qplatformscreen.h b/src/gui/kernel/qplatformscreen.h
index 2e33107fc37172b00c7dab54c8b7cc2882c20376..b32f9cf97c5f6cf02d886becc33ff220459f0526 100644
--- a/src/gui/kernel/qplatformscreen.h
+++ b/src/gui/kernel/qplatformscreen.h
@@ -103,6 +103,7 @@ public:
     virtual QSizeF physicalSize() const;
     virtual QDpi logicalDpi() const;
     virtual qreal devicePixelRatio() const;
+    virtual qreal pixelDensity()  const;
 
     virtual qreal refreshRate() const;
 
@@ -112,6 +113,7 @@ public:
 
     virtual QWindow *topLevelAt(const QPoint &point) const;
     virtual QList<QPlatformScreen *> virtualSiblings() const;
+    const QPlatformScreen *screenForPosition(const QPoint &point) const;
 
     QScreen *screen() const;
 
@@ -131,6 +133,9 @@ public:
     static QTransform transformBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &target);
     static QRect mapBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &rect);
 
+    // The platform screen's geometry in device independent coordinates
+    QRect deviceIndependentGeometry() const;
+
 protected:
     void resizeMaximizedWindows();
 
@@ -139,7 +144,7 @@ protected:
 private:
     Q_DISABLE_COPY(QPlatformScreen)
 
-    friend class QPlatformIntegration;
+    friend class QScreenPrivate;
 };
 
 QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp
index 114fcf8062c6295b51169b5be98cb3071e42efc8..d10bd1e9ebe8e04feb596699b2b8f28e06f20137 100644
--- a/src/gui/kernel/qplatformwindow.cpp
+++ b/src/gui/kernel/qplatformwindow.cpp
@@ -39,8 +39,10 @@
 #include <qpa/qwindowsysteminterface.h>
 #include <QtGui/qwindow.h>
 #include <QtGui/qscreen.h>
+#include <private/qhighdpiscaling_p.h>
 #include <private/qwindow_p.h>
 
+
 QT_BEGIN_NAMESPACE
 
 /*!
@@ -481,13 +483,25 @@ QString QPlatformWindow::formatWindowTitle(const QString &title, const QString &
 QPlatformScreen *QPlatformWindow::screenForGeometry(const QRect &newGeometry) const
 {
     QPlatformScreen *currentScreen = screen();
-    if (!parent() && currentScreen && !currentScreen->geometry().intersects(newGeometry)) {
+    QPlatformScreen *fallback = currentScreen;
+    QPoint center = newGeometry.center();
+    if (!parent() && currentScreen && !currentScreen->geometry().contains(center)) {
         Q_FOREACH (QPlatformScreen* screen, currentScreen->virtualSiblings()) {
-            if (screen->geometry().intersects(newGeometry))
+            if (screen->geometry().contains(center))
                 return screen;
+            if (screen->geometry().intersects(newGeometry))
+                fallback = screen;
         }
     }
-    return currentScreen;
+    return fallback;
+}
+
+/*!
+    Returns a size with both dimensions bounded to [0, QWINDOWSIZE_MAX]
+*/
+QSize QPlatformWindow::constrainWindowSize(const QSize &size)
+{
+    return size.expandedTo(QSize(0, 0)).boundedTo(QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX));
 }
 
 /*!
@@ -565,7 +579,7 @@ void QPlatformWindow::invalidateSurface()
 QRect QPlatformWindow::initialGeometry(const QWindow *w,
     const QRect &initialGeometry, int defaultWidth, int defaultHeight)
 {
-    QRect rect(initialGeometry);
+    QRect rect(QHighDpi::fromNativePixels(initialGeometry, w));
     if (rect.width() == 0) {
         const int minWidth = w->minimumWidth();
         rect.setWidth(minWidth > 0 ? minWidth : defaultWidth);
@@ -593,7 +607,7 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w,
             }
         }
     }
-    return rect;
+    return QHighDpi::toNativePixels(rect, w);
 }
 
 /*!
@@ -626,6 +640,69 @@ void QPlatformWindow::requestUpdate()
     wp->updateTimer = w->startTimer(timeout, Qt::PreciseTimer);
 }
 
+/*!
+    Returns the QWindow minimum size.
+*/
+QSize QPlatformWindow::windowMinimumSize() const
+{
+    return constrainWindowSize(QHighDpi::toNativePixels(window()->minimumSize(), window()));
+}
+
+/*!
+    Returns the QWindow maximum size.
+*/
+QSize QPlatformWindow::windowMaximumSize() const
+{
+    return constrainWindowSize(QHighDpi::toNativePixels(window()->maximumSize(), window()));
+}
+
+/*!
+    Returns the QWindow base size.
+*/
+QSize QPlatformWindow::windowBaseSize() const
+{
+    return QHighDpi::toNativePixels(window()->baseSize(), window());
+}
+
+/*!
+    Returns the QWindow size increment.
+*/
+QSize QPlatformWindow::windowSizeIncrement() const
+{
+    QSize increment = window()->sizeIncrement();
+    if (!QHighDpiScaling::isActive())
+        return increment;
+
+    // Normalize the increment. If not set the increment can be
+    // (-1, -1) or (0, 0). Make that (1, 1) which is scalable.
+    if (increment.isEmpty())
+        increment = QSize(1, 1);
+
+    return QHighDpi::toNativePixels(increment, window());
+}
+
+/*!
+    Returns the QWindow geometry.
+*/
+QRect QPlatformWindow::windowGeometry() const
+{
+    return QHighDpi::toNativePixels(window()->geometry(), window());
+}
+
+/*!
+    Returns the closest acceptable geometry for a given geometry before
+    a resize/move event for platforms that support it, for example to
+    implement heightForWidth().
+*/
+QRectF QPlatformWindow::windowClosestAcceptableGeometry(const QRectF &nativeRect) const
+{
+    QWindow *qWindow = window();
+    const QRectF rectF = QHighDpi::fromNativePixels(nativeRect, qWindow);
+    const QRectF correctedGeometryF = qt_window_private(qWindow)->closestAcceptableGeometry(rectF);
+    return !correctedGeometryF.isEmpty() && rectF != correctedGeometryF
+        ? QHighDpi::toNativePixels(correctedGeometryF, qWindow) : nativeRect;
+}
+
 /*!
     \class QPlatformWindow
     \since 4.8
diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h
index c7c1efdc58e5a4f0013e34cd93166608993441c5..692ae862db55b91d982d850c175db422eb06c124 100644
--- a/src/gui/kernel/qplatformwindow.h
+++ b/src/gui/kernel/qplatformwindow.h
@@ -130,9 +130,20 @@ public:
         const QRect &initialGeometry, int defaultWidth, int defaultHeight);
 
     virtual void requestUpdate();
+
+    // Window property accessors. Platform plugins should use these
+    // instead of accessing QWindow directly.
+    QSize windowMinimumSize() const;
+    QSize windowMaximumSize() const;
+    QSize windowBaseSize() const;
+    QSize windowSizeIncrement() const;
+    QRect windowGeometry() const;
+    QRectF windowClosestAcceptableGeometry(const QRectF &nativeRect) const;
+
 protected:
     static QString formatWindowTitle(const QString &title, const QString &separator);
     QPlatformScreen *screenForGeometry(const QRect &newGeometry) const;
+    static QSize constrainWindowSize(const QSize &size);
 
     QScopedPointer<QPlatformWindowPrivate> d_ptr;
 private:
diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp
index 8398f02a5b81a3f82081fe7ab57916cc2594fdfb..407b4ee9b638a6ced5755c1eb39433e6f2e52456 100644
--- a/src/gui/kernel/qscreen.cpp
+++ b/src/gui/kernel/qscreen.cpp
@@ -36,6 +36,7 @@
 #include "qpixmap.h"
 #include "qguiapplication_p.h"
 #include <qpa/qplatformscreen.h>
+#include <qpa/qplatformscreen_p.h>
 
 #include <QtCore/QDebug>
 #include <QtCore/private/qobject_p.h>
@@ -63,8 +64,33 @@ QT_BEGIN_NAMESPACE
 */
 
 QScreen::QScreen(QPlatformScreen *screen)
-    : QObject(*new QScreenPrivate(screen), 0)
+    : QObject(*new QScreenPrivate(), 0)
 {
+    Q_D(QScreen);
+    d->setPlatformScreen(screen);
+}
+
+void QScreenPrivate::setPlatformScreen(QPlatformScreen *screen)
+{
+    Q_Q(QScreen);
+    platformScreen = screen;
+    platformScreen->d_func()->screen = q;
+    orientation = platformScreen->orientation();
+    geometry = platformScreen->deviceIndependentGeometry();
+    availableGeometry = QHighDpi::fromNative(platformScreen->availableGeometry(), QHighDpiScaling::factor(platformScreen), geometry.topLeft());
+    logicalDpi = platformScreen->logicalDpi();
+    refreshRate = platformScreen->refreshRate();
+    // safeguard ourselves against buggy platform behavior...
+    if (refreshRate < 1.0)
+        refreshRate = 60.0;
+
+    updatePrimaryOrientation();
+
+    filteredOrientation = orientation;
+    if (filteredOrientation == Qt::PrimaryOrientation)
+        filteredOrientation = primaryOrientation;
+
+    updateHighDpi();
 }
 
 
@@ -208,6 +234,8 @@ qreal QScreen::physicalDotsPerInch() const
 qreal QScreen::logicalDotsPerInchX() const
 {
     Q_D(const QScreen);
+    if (QHighDpiScaling::isActive())
+        return QHighDpiScaling::logicalDpi().first;
     return d->logicalDpi.first;
 }
 
@@ -222,6 +250,8 @@ qreal QScreen::logicalDotsPerInchX() const
 qreal QScreen::logicalDotsPerInchY() const
 {
     Q_D(const QScreen);
+    if (QHighDpiScaling::isActive())
+        return QHighDpiScaling::logicalDpi().second;
     return d->logicalDpi.second;
 }
 
@@ -240,7 +270,7 @@ qreal QScreen::logicalDotsPerInchY() const
 qreal QScreen::logicalDotsPerInch() const
 {
     Q_D(const QScreen);
-    QDpi dpi = d->logicalDpi;
+    QDpi dpi = QHighDpiScaling::isActive() ? QHighDpiScaling::logicalDpi() : d->logicalDpi;
     return (dpi.first + dpi.second) * qreal(0.5);
 }
 
@@ -259,7 +289,7 @@ qreal QScreen::logicalDotsPerInch() const
 qreal QScreen::devicePixelRatio() const
 {
     Q_D(const QScreen);
-    return d->platformScreen->devicePixelRatio();
+    return d->platformScreen->devicePixelRatio() * QHighDpiScaling::factor(this);
 }
 
 /*!
diff --git a/src/gui/kernel/qscreen.h b/src/gui/kernel/qscreen.h
index f60fafcf63b226885530904ede3945c1f1a6a038..a6018128e2171293b54b55fb3126547567900a11 100644
--- a/src/gui/kernel/qscreen.h
+++ b/src/gui/kernel/qscreen.h
@@ -154,6 +154,7 @@ private:
     friend class QGuiApplicationPrivate;
     friend class QPlatformIntegration;
     friend class QPlatformScreen;
+    friend class QHighDpiScaling;
 };
 
 #ifndef QT_NO_DEBUG_STREAM
diff --git a/src/gui/kernel/qscreen_p.h b/src/gui/kernel/qscreen_p.h
index d341b71932e3ee8eb329c4e9b62a6cf24609bf36..4492eddd45cda4094d9d4b3ff614493d1cbccbb4 100644
--- a/src/gui/kernel/qscreen_p.h
+++ b/src/gui/kernel/qscreen_p.h
@@ -47,6 +47,7 @@
 
 #include <QtGui/qscreen.h>
 #include <qpa/qplatformscreen.h>
+#include "qhighdpiscaling_p.h"
 
 #include <QtCore/private/qobject_p.h>
 
@@ -54,25 +55,19 @@ QT_BEGIN_NAMESPACE
 
 class QScreenPrivate : public QObjectPrivate
 {
+    Q_DECLARE_PUBLIC(QScreen)
 public:
-    QScreenPrivate(QPlatformScreen *screen)
-        : platformScreen(screen)
+    QScreenPrivate()
+        : platformScreen(0)
         , orientationUpdateMask(0)
     {
-        orientation = platformScreen->orientation();
-        geometry = platformScreen->geometry();
-        availableGeometry = platformScreen->availableGeometry();
-        logicalDpi = platformScreen->logicalDpi();
-        refreshRate = platformScreen->refreshRate();
-        // safeguard ourselves against buggy platform behavior...
-        if (refreshRate < 1.0)
-            refreshRate = 60.0;
-
-        updatePrimaryOrientation();
+    }
 
-        filteredOrientation = orientation;
-        if (filteredOrientation == Qt::PrimaryOrientation)
-            filteredOrientation = primaryOrientation;
+    void setPlatformScreen(QPlatformScreen *screen);
+    void updateHighDpi()
+    {
+        geometry = platformScreen->deviceIndependentGeometry();
+        availableGeometry = QHighDpi::fromNative(platformScreen->availableGeometry(), QHighDpiScaling::factor(platformScreen), geometry.topLeft());
     }
 
     void updatePrimaryOrientation();
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 81e00c8d953a090936c9f15cdec5637c9352fa0c..e93e964c6bc9f8916f380c973c0aaa47615fef03 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -47,6 +47,7 @@
 #ifndef QT_NO_ACCESSIBILITY
 #  include "qaccessible.h"
 #endif
+#include "qhighdpiscaling_p.h"
 
 #include <private/qevent_p.h>
 
@@ -1085,13 +1086,13 @@ qreal QWindow::devicePixelRatio() const
 {
     Q_D(const QWindow);
 
-    // If there is no platform window, do the second best thing and
-    // return the app global devicePixelRatio. This is the highest
-    // devicePixelRatio found on the system screens, and will be
-    // correct for single-display systems (a very common case).
+    // If there is no platform window use the app global devicePixelRatio,
+    // which is the the highest devicePixelRatio found on the system
+    // screens, and will be correct for single-display systems (a very common case).
     if (!d->platformWindow)
         return qApp->devicePixelRatio();
-    return d->platformWindow->devicePixelRatio();
+
+    return d->platformWindow->devicePixelRatio() * QHighDpiScaling::factor(this);
 }
 
 /*!
@@ -1431,7 +1432,13 @@ void QWindow::setGeometry(const QRect &rect)
 
     d->positionPolicy = QWindowPrivate::WindowFrameExclusive;
     if (d->platformWindow) {
-        d->platformWindow->setGeometry(rect);
+        QRect nativeRect;
+        QScreen *newScreen = d->screenForGeometry(rect);
+        if (newScreen && isTopLevel())
+            nativeRect = QHighDpi::toNativePixels(rect, newScreen);
+        else
+            nativeRect = QHighDpi::toNativePixels(rect, this);
+        d->platformWindow->setGeometry(nativeRect);
     } else {
         d->geometry = rect;
 
@@ -1446,6 +1453,30 @@ void QWindow::setGeometry(const QRect &rect)
     }
 }
 
+/*
+  This is equivalent to QPlatformWindow::screenForGeometry, but in platform
+  independent coordinates. The duplication is unfortunate, but there is a
+  chicken and egg problem here: we cannot convert to native coordinates
+  before we know which screen we are on.
+*/
+QScreen *QWindowPrivate::screenForGeometry(const QRect &newGeometry)
+{
+    Q_Q(QWindow);
+    QScreen *currentScreen = q->screen();
+    QScreen *fallback = currentScreen;
+    QPoint center = newGeometry.center();
+    if (!q->parent() && currentScreen && !currentScreen->geometry().contains(center)) {
+        Q_FOREACH (QScreen* screen, currentScreen->virtualSiblings()) {
+            if (screen->geometry().contains(center))
+                return screen;
+            if (screen->geometry().intersects(newGeometry))
+                fallback = screen;
+        }
+    }
+    return fallback;
+}
+
+
 /*!
     Returns the geometry of the window, excluding its window frame.
 
@@ -1455,7 +1486,7 @@ QRect QWindow::geometry() const
 {
     Q_D(const QWindow);
     if (d->platformWindow)
-        return d->platformWindow->geometry();
+        return QHighDpi::fromNativePixels(d->platformWindow->geometry(), this);
     return d->geometry;
 }
 
@@ -1468,7 +1499,7 @@ QMargins QWindow::frameMargins() const
 {
     Q_D(const QWindow);
     if (d->platformWindow)
-        return d->platformWindow->frameMargins();
+        return QHighDpi::fromNativePixels(d->platformWindow->frameMargins(), this);
     return QMargins();
 }
 
@@ -1482,7 +1513,7 @@ QRect QWindow::frameGeometry() const
     Q_D(const QWindow);
     if (d->platformWindow) {
         QMargins m = frameMargins();
-        return d->platformWindow->geometry().adjusted(-m.left(), -m.top(), m.right(), m.bottom());
+        return QHighDpi::fromNativePixels(d->platformWindow->geometry(), this).adjusted(-m.left(), -m.top(), m.right(), m.bottom());
     }
     return d->geometry;
 }
@@ -1499,7 +1530,7 @@ QPoint QWindow::framePosition() const
     Q_D(const QWindow);
     if (d->platformWindow) {
         QMargins margins = frameMargins();
-        return d->platformWindow->geometry().topLeft() - QPoint(margins.left(), margins.top());
+        return QHighDpi::fromNativePixels(d->platformWindow->geometry().topLeft(), this) - QPoint(margins.left(), margins.top());
     }
     return d->geometry.topLeft();
 }
@@ -1515,7 +1546,7 @@ void QWindow::setFramePosition(const QPoint &point)
     d->positionPolicy = QWindowPrivate::WindowFrameInclusive;
     d->positionAutomatic = false;
     if (d->platformWindow) {
-        d->platformWindow->setGeometry(QRect(point, size()));
+        d->platformWindow->setGeometry(QHighDpi::toNativePixels(QRect(point, size()), this));
     } else {
         d->geometry.moveTopLeft(point);
     }
@@ -1575,7 +1606,7 @@ void QWindow::resize(const QSize &newSize)
 {
     Q_D(QWindow);
     if (d->platformWindow) {
-        d->platformWindow->setGeometry(QRect(position(), newSize));
+        d->platformWindow->setGeometry(QHighDpi::toNativePixels(QRect(position(), newSize), this));
     } else {
         const QSize oldSize = d->geometry.size();
         d->geometry.setSize(newSize);
diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h
index 4fc63acf28f16ba1c41f2f0194c45ee335039217..23a6d800c01d3e2152cd75b4b22563f157816fca 100644
--- a/src/gui/kernel/qwindow_p.h
+++ b/src/gui/kernel/qwindow_p.h
@@ -136,6 +136,7 @@ public:
     void connectToScreen(QScreen *topLevelScreen);
     void disconnectFromScreen();
     void emitScreenChangedRecursion(QScreen *newScreen);
+    QScreen *screenForGeometry(const QRect &rect);
 
     virtual void clearFocusObject();
     virtual QRectF closestAcceptableGeometry(const QRectF &rect) const;
diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp
index 17bce6c70fdf9cf3c097e4a9fe872c226c424e19..5877467830aac19c8d2bd4104ecf84d02c1b8b0d 100644
--- a/src/gui/kernel/qwindowsysteminterface.cpp
+++ b/src/gui/kernel/qwindowsysteminterface.cpp
@@ -40,6 +40,7 @@
 #include <qpa/qplatformdrag.h>
 #include <qpa/qplatformintegration.h>
 #include <qdebug.h>
+#include "qhighdpiscaling_p.h"
 
 QT_BEGIN_NAMESPACE
 
@@ -139,7 +140,7 @@ void QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState
  */
 void QWindowSystemInterface::handleGeometryChange(QWindow *tlw, const QRect &newRect, const QRect &oldRect)
 {
-    QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(tlw,newRect, oldRect);
+    QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(tlw, QHighDpi::fromNativePixels(newRect, tlw), QHighDpi::fromNativePixels(oldRect, tlw));
     QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
 }
 
@@ -168,7 +169,7 @@ void QWindowSystemInterface::handleMouseEvent(QWindow *w, ulong timestamp, const
                                               Qt::KeyboardModifiers mods, Qt::MouseEventSource source)
 {
     QWindowSystemInterfacePrivate::MouseEvent * e =
-        new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp, local, global, b, mods, source);
+        new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp, QHighDpi::fromNativeLocalPosition(local, w), QHighDpi::fromNativePixels(global, w), b, mods, source);
     QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
 }
 
@@ -185,7 +186,7 @@ void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *w, ulong timest
     QWindowSystemInterfacePrivate::MouseEvent * e =
             new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp,
                                                           QWindowSystemInterfacePrivate::FrameStrutMouse,
-                                                          local, global, b, mods, source);
+                                                          QHighDpi::fromNativeLocalPosition(local, w), QHighDpi::fromNativePixels(global, w), b, mods, source);
     QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
 }
 
@@ -366,14 +367,14 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con
 
     // Simple case: vertical deltas only:
     if (angleDelta.y() != 0 && angleDelta.x() == 0) {
-        e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source);
+        e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source);
         QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
         return;
     }
 
     // Simple case: horizontal deltas only:
     if (angleDelta.y() == 0 && angleDelta.x() != 0) {
-        e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods, phase, source);
+        e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods, phase, source);
         QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
         return;
     }
@@ -381,12 +382,12 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con
     // Both horizontal and vertical deltas: Send two wheel events.
     // The first event contains the Qt 5 pixel and angle delta as points,
     // and in addition the Qt 4 compatibility vertical angle delta.
-    e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source);
+    e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source);
     QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
 
     // The second event contains null pixel and angle points and the
     // Qt 4 compatibility horizontal angle delta.
-    e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods, phase, source);
+    e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods, phase, source);
     QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
 }
 
@@ -449,7 +450,10 @@ void QWindowSystemInterface::handleTouchEvent(QWindow *w, QTouchDevice *device,
     handleTouchEvent(w, time, device, points, mods);
 }
 
-QList<QTouchEvent::TouchPoint> QWindowSystemInterfacePrivate::convertTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points, QEvent::Type *type)
+QList<QTouchEvent::TouchPoint>
+    QWindowSystemInterfacePrivate::fromNativeTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points,
+                                                         const QWindow *window,
+                                                         QEvent::Type *type)
 {
     QList<QTouchEvent::TouchPoint> touchPoints;
     Qt::TouchPointStates states;
@@ -465,16 +469,16 @@ QList<QTouchEvent::TouchPoint> QWindowSystemInterfacePrivate::convertTouchPoints
         p.setState(point->state);
 
         const QPointF screenPos = point->area.center();
-        p.setScreenPos(screenPos);
-        p.setScreenRect(point->area);
+        p.setScreenPos(QHighDpi::fromNativePixels(screenPos, window));
+        p.setScreenRect(QHighDpi::fromNativePixels(point->area, window));
 
         // The local pos and rect are not set, they will be calculated
         // when the event gets processed by QGuiApplication.
 
-        p.setNormalizedPos(point->normalPosition);
-        p.setVelocity(point->velocity);
+        p.setNormalizedPos(QHighDpi::fromNativePixels(point->normalPosition, window));
+        p.setVelocity(QHighDpi::fromNativePixels(point->velocity, window));
         p.setFlags(point->flags);
-        p.setRawScreenPositions(point->rawPositions);
+        p.setRawScreenPositions(QHighDpi::fromNativePixels(point->rawPositions, window));
 
         touchPoints.append(p);
         ++point;
@@ -492,6 +496,27 @@ QList<QTouchEvent::TouchPoint> QWindowSystemInterfacePrivate::convertTouchPoints
     return touchPoints;
 }
 
+QList<QWindowSystemInterface::TouchPoint>
+    QWindowSystemInterfacePrivate::toNativeTouchPoints(const QList<QTouchEvent::TouchPoint>& pointList,
+                                                       const QWindow *window)
+{
+    QList<QWindowSystemInterface::TouchPoint> newList;
+    newList.reserve(pointList.size());
+    foreach (const QTouchEvent::TouchPoint &pt, pointList) {
+        QWindowSystemInterface::TouchPoint p;
+        p.id = pt.id();
+        p.flags = pt.flags();
+        p.normalPosition = QHighDpi::toNativeLocalPosition(pt.normalizedPos(), window);
+        p.area = QHighDpi::toNativePixels(pt.screenRect(), window);
+        p.pressure = pt.pressure();
+        p.state = pt.state();
+        p.velocity = pt.velocity();
+        p.rawPositions = pt.rawScreenPositions();
+        newList.append(p);
+    }
+    return newList;
+}
+
 void QWindowSystemInterface::handleTouchEvent(QWindow *tlw, ulong timestamp, QTouchDevice *device,
                                               const QList<TouchPoint> &points, Qt::KeyboardModifiers mods)
 {
@@ -502,7 +527,7 @@ void QWindowSystemInterface::handleTouchEvent(QWindow *tlw, ulong timestamp, QTo
         return;
 
     QEvent::Type type;
-    QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::convertTouchPoints(points, &type);
+    QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, tlw, &type);
 
     QWindowSystemInterfacePrivate::TouchEvent *e =
             new QWindowSystemInterfacePrivate::TouchEvent(tlw, timestamp, type, device, touchPoints, mods);
@@ -535,14 +560,14 @@ void QWindowSystemInterface::handleScreenOrientationChange(QScreen *screen, Qt::
 void QWindowSystemInterface::handleScreenGeometryChange(QScreen *screen, const QRect &geometry, const QRect &availableGeometry)
 {
     QWindowSystemInterfacePrivate::ScreenGeometryEvent *e =
-            new QWindowSystemInterfacePrivate::ScreenGeometryEvent(screen, geometry, availableGeometry);
+        new QWindowSystemInterfacePrivate::ScreenGeometryEvent(screen, QHighDpi::fromNativeScreenGeometry(geometry, screen), QHighDpi::fromNative(availableGeometry, screen, geometry.topLeft()));
     QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
 }
 
 void QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(QScreen *screen, qreal dpiX, qreal dpiY)
 {
     QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *e =
-            new QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent(screen, dpiX, dpiY);
+            new QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent(screen, dpiX, dpiY); // ### tja
     QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
 }
 
@@ -561,7 +586,7 @@ void QWindowSystemInterface::handleThemeChange(QWindow *tlw)
 
 void QWindowSystemInterface::handleExposeEvent(QWindow *tlw, const QRegion &region)
 {
-    QWindowSystemInterfacePrivate::ExposeEvent *e = new QWindowSystemInterfacePrivate::ExposeEvent(tlw, region);
+    QWindowSystemInterfacePrivate::ExposeEvent *e = new QWindowSystemInterfacePrivate::ExposeEvent(tlw, QHighDpi::fromNativeLocalRegion(region, tlw));
     QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
 }
 
@@ -646,12 +671,12 @@ int QWindowSystemInterface::windowSystemEventsQueued()
 #ifndef QT_NO_DRAGANDDROP
 QPlatformDragQtResponse QWindowSystemInterface::handleDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions)
 {
-    return QGuiApplicationPrivate::processDrag(w, dropData, p,supportedActions);
+    return QGuiApplicationPrivate::processDrag(w, dropData, QHighDpi::fromNativeLocalPosition(p, w) ,supportedActions);
 }
 
 QPlatformDropQtResponse QWindowSystemInterface::handleDrop(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions)
 {
-    return QGuiApplicationPrivate::processDrop(w, dropData, p,supportedActions);
+    return QGuiApplicationPrivate::processDrop(w, dropData, QHighDpi::fromNativeLocalPosition(p, w),supportedActions);
 }
 #endif // QT_NO_DRAGANDDROP
 
@@ -685,8 +710,11 @@ void QWindowSystemInterface::handleTabletEvent(QWindow *w, ulong timestamp, cons
                                                Qt::KeyboardModifiers modifiers)
 {
     QWindowSystemInterfacePrivate::TabletEvent *e =
-            new QWindowSystemInterfacePrivate::TabletEvent(w, timestamp, local, global, device, pointerType, buttons, pressure,
-                                                           xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers);
+        new QWindowSystemInterfacePrivate::TabletEvent(w,timestamp,
+                                                       QHighDpi::fromNativeLocalPosition(local, w),
+                                                       QHighDpi::fromNativePixels(global, w),
+                                                       device, pointerType, buttons, pressure,
+                                                       xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers);
     QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
 }
 
@@ -838,7 +866,6 @@ Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int
     return QWindowSystemInterface::tryHandleShortcutEventToObject(o, timestamp, k, mods, text, autorep, count);
 }
 
-
 Q_GUI_EXPORT void qt_handleTouchEvent(QWindow *w, QTouchDevice *device,
                                 const QList<QTouchEvent::TouchPoint> &points,
                                 Qt::KeyboardModifiers mods = Qt::NoModifier)
@@ -883,4 +910,5 @@ bool QWindowSystemEventHandler::sendEvent(QWindowSystemInterfacePrivate::WindowS
     return true;
 }
 
+
 QT_END_NAMESPACE
diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h
index 71609713050d35d200b950ab678aab3e3194ea0b..cbc3bad7cda7f0767d7b4c25949402f21c505614 100644
--- a/src/gui/kernel/qwindowsysteminterface_p.h
+++ b/src/gui/kernel/qwindowsysteminterface_p.h
@@ -488,7 +488,12 @@ public:
     static QWaitCondition eventsFlushed;
     static QMutex flushEventMutex;
 
-    static QList<QTouchEvent::TouchPoint> convertTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points, QEvent::Type *type);
+    static QList<QTouchEvent::TouchPoint>
+        fromNativeTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points,
+                              const QWindow *window, QEvent::Type *type = Q_NULLPTR);
+    static QList<QWindowSystemInterface::TouchPoint>
+        toNativeTouchPoints(const QList<QTouchEvent::TouchPoint>& pointList,
+                            const QWindow *window);
 
     static void installWindowSystemEventHandler(QWindowSystemEventHandler *handler);
     static void removeWindowSystemEventhandler(QWindowSystemEventHandler *handler);
diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp
index 19074e4c47c4831a79d3256c67b2372e6254932c..4136c29d4e004f370003925027a1712723c45163 100644
--- a/src/gui/painting/qbackingstore.cpp
+++ b/src/gui/painting/qbackingstore.cpp
@@ -38,10 +38,13 @@
 #include <qpa/qplatformintegration.h>
 #include <qscreen.h>
 #include <qdebug.h>
+#include <qscopedpointer.h>
 
 #include <private/qguiapplication_p.h>
 #include <private/qwindow_p.h>
 
+#include <private/qhighdpiscaling_p.h>
+
 QT_BEGIN_NAMESPACE
 
 class QBackingStorePrivate
@@ -54,6 +57,7 @@ public:
 
     QWindow *window;
     QPlatformBackingStore *platformBackingStore;
+    QScopedPointer<QImage> highDpiBackingstore;
     QRegion staticContents;
     QSize size;
 };
@@ -102,7 +106,7 @@ void QBackingStore::flush(const QRegion &region, QWindow *win, const QPoint &off
     }
 #endif
 
-    d_ptr->platformBackingStore->flush(win, region, offset);
+    d_ptr->platformBackingStore->flush(win, QHighDpi::toNativeLocalRegion(region, d_ptr->window), offset);
 }
 
 /*!
@@ -112,7 +116,12 @@ void QBackingStore::flush(const QRegion &region, QWindow *win, const QPoint &off
 */
 QPaintDevice *QBackingStore::paintDevice()
 {
-    return d_ptr->platformBackingStore->paintDevice();
+    QPaintDevice *device = d_ptr->platformBackingStore->paintDevice();
+
+    if (QHighDpiScaling::isActive() && device->devType() == QInternal::Image)
+        return d_ptr->highDpiBackingstore.data();
+
+    return device;
 }
 
 /*!
@@ -150,7 +159,36 @@ QWindow* QBackingStore::window() const
 
 void QBackingStore::beginPaint(const QRegion &region)
 {
-    d_ptr->platformBackingStore->beginPaint(region);
+    if (d_ptr->highDpiBackingstore &&
+        d_ptr->highDpiBackingstore->devicePixelRatio() != d_ptr->window->devicePixelRatio())
+        resize(size());
+
+    d_ptr->platformBackingStore->beginPaint(QHighDpi::toNativeLocalRegion(region, d_ptr->window));
+
+    // When QtGui is applying a high-dpi scale factor the backing store
+    // creates a "large" backing store image. This image needs to be
+    // painted on as a high-dpi image, which is done by setting
+    // devicePixelRatio. Do this on a separate image instance that shares
+    // the image data to avoid having the new devicePixelRatio be propagated
+    // back to the platform plugin.
+    QPaintDevice *device = d_ptr->platformBackingStore->paintDevice();
+    if (QHighDpiScaling::isActive() && device->devType() == QInternal::Image) {
+        QImage *source = static_cast<QImage *>(device);
+        const bool needsNewImage = d_ptr->highDpiBackingstore.isNull()
+            || source->data_ptr() != d_ptr->highDpiBackingstore->data_ptr()
+            || source->size() != d_ptr->highDpiBackingstore->size()
+            || source->devicePixelRatio() != d_ptr->highDpiBackingstore->devicePixelRatio();
+        if (needsNewImage) {
+            qCDebug(lcScaling) << "QBackingStore::beginPaint new backingstore for" << d_ptr->window;
+            qCDebug(lcScaling) << "  source size" << source->size() << "dpr" << source->devicePixelRatio();
+            d_ptr->highDpiBackingstore.reset(
+                new QImage(source->bits(), source->width(), source->height(), source->format()));
+            qreal targetDevicePixelRatio = d_ptr->window->devicePixelRatio();
+            d_ptr->highDpiBackingstore->setDevicePixelRatio(targetDevicePixelRatio);
+            qCDebug(lcScaling) <<"  destination size" << d_ptr->highDpiBackingstore->size()
+                               << "dpr" << targetDevicePixelRatio;
+        }
+    }
 }
 
 /*!
@@ -171,7 +209,7 @@ void QBackingStore::endPaint()
 void QBackingStore::resize(const QSize &size)
 {
     d_ptr->size = size;
-    d_ptr->platformBackingStore->resize(size, d_ptr->staticContents);
+    d_ptr->platformBackingStore->resize(QHighDpi::toNativePixels(size, d_ptr->window), d_ptr->staticContents);
 }
 
 /*!
@@ -194,7 +232,7 @@ bool QBackingStore::scroll(const QRegion &area, int dx, int dy)
     Q_UNUSED(dx);
     Q_UNUSED(dy);
 
-    return d_ptr->platformBackingStore->scroll(area, dx, dy);
+    return d_ptr->platformBackingStore->scroll(QHighDpi::toNativeLocalRegion(area, d_ptr->window), QHighDpi::toNativePixels(dx, d_ptr->window), QHighDpi::toNativePixels(dy, d_ptr->window));
 }
 
 void QBackingStore::setStaticContents(const QRegion &region)
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 06c42ff0416ed09c461fb470e7ece3db744dc5a5..9195c1e5fa40a28af92028fcd855b840f115cab1 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -68,6 +68,7 @@
 #include "private/qstylesheetstyle_p.h"
 #include "private/qstyle_p.h"
 #include "qfileinfo.h"
+#include <QtGui/private/qhighdpiscaling_p.h>
 #include <QtGui/qinputmethod.h>
 #include <QtGui/qopenglcontext.h>
 #include <QtGui/private/qopenglcontext_p.h>
@@ -12774,7 +12775,7 @@ void QWidgetPrivate::setMask_sys(const QRegion &region)
     Q_Q(QWidget);
     if (const QWindow *window = q->windowHandle())
         if (QPlatformWindow *platformWindow = window->handle())
-            platformWindow->setMask(region);
+            platformWindow->setMask(QHighDpi::toNativeLocalRegion(region, window));
 }
 
 /*!
diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp
index 01d6d8985729e37748e4b0474c91177249c9b823..633e7108530ff690eca7a234e9f8417a711f5554 100644
--- a/src/widgets/kernel/qwidgetwindow.cpp
+++ b/src/widgets/kernel/qwidgetwindow.cpp
@@ -45,6 +45,7 @@
 #include <qpa/qplatformtheme.h>
 #include <qpa/qplatformwindow.h>
 #include <private/qgesturemanager_p.h>
+#include <private/qhighdpiscaling_p.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -671,7 +672,7 @@ void QWidgetWindow::updateNormalGeometry()
      // Ask platform window, default to widget geometry.
     QRect normalGeometry;
     if (const QPlatformWindow *pw = handle())
-        normalGeometry = pw->normalGeometry();
+        normalGeometry = QHighDpi::fromNativePixels(pw->normalGeometry(), this);
     if (!normalGeometry.isValid() && effectiveState(m_widget->windowState()) == Qt::WindowNoState)
         normalGeometry = m_widget->geometry();
     if (normalGeometry.isValid())