From a705b4ec1f6f7133390054f8b6b8077ef0550311 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?=
 <morten.sorvig@theqtcompany.com>
Date: Mon, 22 Jun 2015 12:32:11 +0200
Subject: [PATCH] Introduce cross platform high-dpi scaling

Add a coordinate scaling layer to QtGui, which supports 'devicePixelRatio'
type high-dpi on all platforms, in production and also for
development and testing purposes.

High-DPI scaling is opt-in, by setting environment variables:
    QT_SCALE_FACTOR - sets a global scale factor
    QT_AUTO_SCREEN_SCALE_FACTOR - sets per-screen scale factors,
        where the scale factors are provided by the platform plugin.

This QtGui scaling can be used instead of or in addition to scaling
done by the window system. This distinction is not visible to
applications [when they use Qt API], which will see a change in
the value returned by the devicePixelRatio() accessors as usual.

Introduce a new (private to Qt) coordinate system: native pixels.
The coordinate system stack now looks like:
    device-independent pixels (app, upper parts of Qt)
    native pixels (lower parts of Qt Gui, platform plugins)
    device pixels (backing stores and OpenGL)

Add private QHighDpi namespace with scaling functions that convert
between device-independent pixels and native pixels:
    T toNativePixels(T, QWindow *);
    T fromNativePixels(T, QWindow *);

Add scaling calls the QWindow (and friends) cross-platform implementation,
around the calls to QPlatformWindow functions. QPlatformWindow now uses
native coordinates - platform code remains largely unchanged since native
coordinates are window system coordinates.

QWindow now uses (possibly) scaled coordinates. This means that
platform plugins no longer can rely on QWindow::geometry() and
related functions. QPlatformWindow::windowGeometry() and other
convenience functions have been added for use when the platform
plugin needs to convert scaled geometry to native geometry.

Add Qt::AA_NoHighDpiScaling, which can be use to disable any
scaling in QtGui, effectively ignoring the environment variables.
(Note that this does not disable any scaling done by the window
system.)

Contributions from Friedemann and Paul.

Task-number: QTBUG-46615
Change-Id: I673bbd69c130e73b13cce83be11bfb28f580bf60
Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
---
 src/corelib/global/qnamespace.h           |   1 +
 src/corelib/global/qnamespace.qdoc        |   5 +
 src/gui/kernel/kernel.pri                 |   8 +-
 src/gui/kernel/qcursor.cpp                |  18 +-
 src/gui/kernel/qguiapplication.cpp        |  18 +-
 src/gui/kernel/qhighdpiscaling.cpp        | 320 ++++++++++++++++++++
 src/gui/kernel/qhighdpiscaling_p.h        | 470 ++++++++++++++++++++++++++++++
 src/gui/kernel/qplatformintegration.cpp   |   8 +-
 src/gui/kernel/qplatformscreen.cpp        |  57 +++-
 src/gui/kernel/qplatformscreen.h          |   7 +-
 src/gui/kernel/qplatformwindow.cpp        |  87 +++++-
 src/gui/kernel/qplatformwindow.h          |  11 +
 src/gui/kernel/qscreen.cpp                |  36 ++-
 src/gui/kernel/qscreen.h                  |   1 +
 src/gui/kernel/qscreen_p.h                |  25 +-
 src/gui/kernel/qwindow.cpp                |  55 +++-
 src/gui/kernel/qwindow_p.h                |   1 +
 src/gui/kernel/qwindowsysteminterface.cpp |  72 +++--
 src/gui/kernel/qwindowsysteminterface_p.h |   7 +-
 src/gui/painting/qbackingstore.cpp        |  48 ++-
 src/widgets/kernel/qwidget.cpp            |   3 +-
 src/widgets/kernel/qwidgetwindow.cpp      |   3 +-
 22 files changed, 1174 insertions(+), 87 deletions(-)
 create mode 100644 src/gui/kernel/qhighdpiscaling.cpp
 create mode 100644 src/gui/kernel/qhighdpiscaling_p.h

Index: b/src/corelib/global/qnamespace.h
===================================================================
--- 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
Index: b/src/corelib/global/qnamespace.qdoc
===================================================================
--- 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
Index: b/src/gui/kernel/kernel.pri
===================================================================
--- 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 += \
Index: b/src/gui/kernel/qcursor.cpp
===================================================================
--- 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, in
 {
     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);
         }
     }
 }
Index: b/src/gui/kernel/qguiapplication.cpp
===================================================================
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -958,8 +958,10 @@ QWindow *QGuiApplication::topLevelAt(con
     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;
@@ -1115,6 +1117,9 @@ void QGuiApplicationPrivate::createPlatf
     // this flag.
     QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true);
 
+
+    QHighDpiScaling::initHighDpiScaling();
+
     // Load the platform integration
     QString platformPluginPath = QLatin1String(qgetenv("QT_QPA_PLATFORM_PLUGIN_PATH"));
 
@@ -1177,6 +1182,8 @@ void QGuiApplicationPrivate::createPlatf
 
     if (!icon.isEmpty())
         forcedWindowIcon = QDir::isAbsolutePath(icon) ? QIcon(icon) : QIcon::fromTheme(icon);
+
+    QHighDpiScaling::updateHighDpiScaling();
 }
 
 /*!
@@ -1815,7 +1822,7 @@ void QGuiApplicationPrivate::processMous
         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::processWind
             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);
+        }
     }
 }
 
Index: b/src/gui/kernel/qhighdpiscaling.cpp
===================================================================
--- /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
Index: b/src/gui/kernel/qhighdpiscaling_p.h
===================================================================
--- /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
Index: b/src/gui/kernel/qplatformintegration.cpp
===================================================================
--- 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::possibl
 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(Q
 */
 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;
 }
 
Index: b/src/gui/kernel/qplatformscreen.cpp
===================================================================
--- 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
 
@@ -97,6 +98,23 @@ QWindow *QPlatformScreen::topLevelAt(con
 }
 
 /*!
+  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,11 +174,13 @@ 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
 {
@@ -168,6 +188,24 @@ qreal QPlatformScreen::devicePixelRatio(
 }
 
 /*!
+    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::resizeMaximizedWin
     // '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::Sc
     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.
 
Index: b/src/gui/kernel/qplatformscreen.h
===================================================================
--- a/src/gui/kernel/qplatformscreen.h
+++ b/src/gui/kernel/qplatformscreen.h
@@ -96,6 +96,7 @@ public:
     virtual QSizeF physicalSize() const;
     virtual QDpi logicalDpi() const;
     virtual qreal devicePixelRatio() const;
+    virtual qreal pixelDensity()  const;
 
     virtual qreal refreshRate() const;
 
@@ -105,6 +106,7 @@ public:
 
     virtual QWindow *topLevelAt(const QPoint &point) const;
     virtual QList<QPlatformScreen *> virtualSiblings() const;
+    const QPlatformScreen *screenForPosition(const QPoint &point) const;
 
     QScreen *screen() const;
 
@@ -121,6 +123,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();
 
@@ -129,7 +134,7 @@ protected:
 private:
     Q_DISABLE_COPY(QPlatformScreen)
 
-    friend class QPlatformIntegration;
+    friend class QScreenPrivate;
 };
 
 QT_END_NAMESPACE
Index: b/src/gui/kernel/qplatformwindow.cpp
===================================================================
--- 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::formatWindowTit
 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(c
             }
         }
     }
-    return rect;
+    return QHighDpi::toNativePixels(rect, w);
 }
 
 /*!
@@ -627,6 +641,69 @@ void QPlatformWindow::requestUpdate()
 }
 
 /*!
+    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
     \internal
Index: b/src/gui/kernel/qplatformwindow.h
===================================================================
--- 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:
Index: b/src/gui/kernel/qscreen.cpp
===================================================================
--- 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/private/qobject_p.h>
 
@@ -62,8 +63,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();
 }
 
 
@@ -207,6 +233,8 @@ qreal QScreen::physicalDotsPerInch() con
 qreal QScreen::logicalDotsPerInchX() const
 {
     Q_D(const QScreen);
+    if (QHighDpiScaling::isActive())
+        return QHighDpiScaling::logicalDpi().first;
     return d->logicalDpi.first;
 }
 
@@ -221,6 +249,8 @@ qreal QScreen::logicalDotsPerInchX() con
 qreal QScreen::logicalDotsPerInchY() const
 {
     Q_D(const QScreen);
+    if (QHighDpiScaling::isActive())
+        return QHighDpiScaling::logicalDpi().second;
     return d->logicalDpi.second;
 }
 
@@ -239,7 +269,7 @@ qreal QScreen::logicalDotsPerInchY() con
 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);
 }
 
@@ -258,7 +288,7 @@ qreal QScreen::logicalDotsPerInch() cons
 qreal QScreen::devicePixelRatio() const
 {
     Q_D(const QScreen);
-    return d->platformScreen->devicePixelRatio();
+    return d->platformScreen->devicePixelRatio() * QHighDpiScaling::factor(this);
 }
 
 /*!
Index: b/src/gui/kernel/qscreen.h
===================================================================
--- a/src/gui/kernel/qscreen.h
+++ b/src/gui/kernel/qscreen.h
@@ -151,6 +151,7 @@ private:
     friend class QGuiApplicationPrivate;
     friend class QPlatformIntegration;
     friend class QPlatformScreen;
+    friend class QHighDpiScaling;
 };
 
 QT_END_NAMESPACE
Index: b/src/gui/kernel/qscreen_p.h
===================================================================
--- 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();
Index: b/src/gui/kernel/qwindow.cpp
===================================================================
--- 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 &r
 
     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 &r
     }
 }
 
+/*
+  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 QPo
     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 &newSiz
 {
     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);
Index: b/src/gui/kernel/qwindow_p.h
===================================================================
--- 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;
Index: b/src/gui/kernel/qwindowsysteminterface.cpp
===================================================================
--- 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
 
@@ -138,7 +139,7 @@ void QWindowSystemInterface::handleAppli
  */
 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);
 }
 
@@ -167,7 +168,7 @@ void QWindowSystemInterface::handleMouse
                                               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);
 }
 
@@ -184,7 +185,7 @@ void QWindowSystemInterface::handleFrame
     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);
 }
 
@@ -382,14 +383,14 @@ void QWindowSystemInterface::handleWheel
 
     // 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;
     }
@@ -397,12 +398,12 @@ void QWindowSystemInterface::handleWheel
     // 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);
 }
 
@@ -464,7 +465,10 @@ void QWindowSystemInterface::handleTouch
     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;
@@ -479,16 +483,16 @@ QList<QTouchEvent::TouchPoint> QWindowSy
         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;
@@ -506,6 +510,27 @@ QList<QTouchEvent::TouchPoint> QWindowSy
     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)
 {
@@ -516,7 +541,7 @@ void QWindowSystemInterface::handleTouch
         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);
@@ -549,14 +574,14 @@ void QWindowSystemInterface::handleScree
 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);
 }
 
@@ -575,7 +600,7 @@ void QWindowSystemInterface::handleTheme
 
 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);
 }
 
@@ -642,12 +667,12 @@ int QWindowSystemInterface::windowSystem
 #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
 
@@ -681,8 +706,11 @@ void QWindowSystemInterface::handleTable
                                                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);
 }
 
@@ -852,4 +880,5 @@ Q_GUI_EXPORT  void qt_handleTouchEvent(Q
     QWindowSystemInterface::handleTouchEvent(w, device, touchPointList(points), mods);
 }
 
+
 QT_END_NAMESPACE
Index: b/src/gui/painting/qbackingstore.cpp
===================================================================
--- 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
     }
 #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
 */
 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
     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));
 }
 
 /*!
Index: b/src/widgets/kernel/qwidget.cpp
===================================================================
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -69,6 +69,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>
@@ -12769,7 +12770,7 @@ void QWidgetPrivate::setMask_sys(const Q
     Q_Q(QWidget);
     if (const QWindow *window = q->windowHandle())
         if (QPlatformWindow *platformWindow = window->handle())
-            platformWindow->setMask(region);
+            platformWindow->setMask(QHighDpi::toNativeLocalRegion(region, window));
 }
 
 /*!
Index: b/src/widgets/kernel/qwidgetwindow.cpp
===================================================================
--- 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
 
@@ -681,7 +682,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())
Index: b/src/gui/kernel/qwindowsysteminterface_p.h
===================================================================
--- a/src/gui/kernel/qwindowsysteminterface_p.h
+++ b/src/gui/kernel/qwindowsysteminterface_p.h
@@ -486,7 +486,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);
 };
 
 QT_END_NAMESPACE
