1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QHIGHDPISCALING_P_H
41#define QHIGHDPISCALING_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists purely as an
48// implementation detail. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include <QtGui/private/qtguiglobal_p.h>
55#include <QtCore/qmargins.h>
56#include <QtCore/qmath.h>
57#include <QtCore/qrect.h>
58#include <QtCore/qvector.h>
59#include <QtCore/qloggingcategory.h>
60#include <QtGui/qregion.h>
61#include <QtGui/qscreen.h>
62#include <QtGui/qwindow.h>
63
64QT_BEGIN_NAMESPACE
65
66Q_DECLARE_LOGGING_CATEGORY(lcScaling);
67
68class QScreen;
69class QPlatformScreen;
70typedef QPair<qreal, qreal> QDpi;
71
72#ifndef QT_NO_HIGHDPISCALING
73class Q_GUI_EXPORT QHighDpiScaling {
74public:
75 static void initHighDpiScaling();
76 static void updateHighDpiScaling();
77 static void setGlobalFactor(qreal factor);
78 static void setScreenFactor(QScreen *window, qreal factor);
79
80 static bool isActive() { return m_active; }
81
82 struct ScaleAndOrigin
83 {
84 qreal factor;
85 QPoint origin;
86 };
87 static ScaleAndOrigin scaleAndOrigin(const QPlatformScreen *platformScreen, QPoint *nativePosition = nullptr);
88 static ScaleAndOrigin scaleAndOrigin(const QScreen *screen, QPoint *nativePosition = nullptr);
89 static ScaleAndOrigin scaleAndOrigin(const QWindow *platformScreen, QPoint *nativePosition = nullptr);
90
91 template<typename C>
92 static qreal factor(C *context, QPoint *nativePosition = nullptr) {
93 return scaleAndOrigin(context, nativePosition).factor;
94 }
95
96 static QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen);
97 static QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen);
98 static QPoint mapPositionToGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window);
99 static QPoint mapPositionFromGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window);
100 static QDpi logicalDpi();
101
102private:
103 static qreal screenSubfactor(const QPlatformScreen *screen);
104
105 static qreal m_factor;
106 static bool m_active;
107 static bool m_usePixelDensity;
108 static bool m_globalScalingActive;
109 static bool m_pixelDensityScalingActive;
110 static bool m_screenFactorSet;
111 static QDpi m_logicalDpi;
112};
113
114// Coordinate system conversion functions:
115// QHighDpi::fromNativePixels : from physical(screen/backing) to logical pixels
116// QHighDpi::toNativePixels : from logical to physical pixels
117
118namespace QHighDpi {
119
120template <typename T>
121inline T scale(const T &value, qreal scaleFactor, QPoint origin = QPoint(0, 0))
122{
123 Q_UNUSED(origin)
124 return value * scaleFactor;
125}
126
127inline QPointF scale(const QPointF &pos, qreal scaleFactor, QPointF origin = QPointF(0, 0))
128{
129 return (pos - origin) * scaleFactor + origin;
130}
131
132inline QPoint scale(const QPoint &pos, qreal scaleFactor, QPoint origin = QPoint(0, 0))
133{
134 return (pos - origin) * scaleFactor + origin;
135}
136
137inline QRect scale(const QRect &rect, qreal scaleFactor, QPoint origin = QPoint(0, 0))
138{
139 return QRect(scale(rect.topLeft(), scaleFactor, origin), scale(rect.size(), scaleFactor));
140}
141
142inline QRectF scale(const QRectF &rect, qreal scaleFactor, QPoint origin = QPoint(0, 0))
143{
144 return QRectF(scale(rect.topLeft(), scaleFactor, origin), scale(rect.size(), scaleFactor));
145}
146
147inline QMargins scale(const QMargins &margins, qreal scaleFactor, QPoint origin = QPoint(0, 0))
148{
149 Q_UNUSED(origin)
150 return QMargins(qRound(qreal(margins.left()) * scaleFactor), qRound(qreal(margins.top()) * scaleFactor),
151 qRound(qreal(margins.right()) * scaleFactor), qRound(qreal(margins.bottom()) * scaleFactor));
152}
153
154template <typename T>
155QVector<T> scale(const QVector<T> &vector, qreal scaleFactor, QPoint origin = QPoint(0, 0))
156{
157 if (!QHighDpiScaling::isActive())
158 return vector;
159
160 QVector<T> scaled;
161 scaled.reserve(vector.size());
162 for (const T &item : vector)
163 scaled.append(scale(item, scaleFactor, origin));
164 return scaled;
165}
166
167inline QRegion scale(const QRegion &region, qreal scaleFactor, QPoint origin = QPoint(0, 0))
168{
169 if (!QHighDpiScaling::isActive())
170 return region;
171
172 QRegion scaled;
173 for (const QRect &rect : region)
174 scaled += scale(rect, scaleFactor, origin);
175 return scaled;
176}
177
178template <typename T>
179inline QPoint position(T) { return QPoint(); }
180inline QPoint position(QPoint point) { return point; }
181inline QPoint position(QPointF point) { return point.toPoint(); }
182inline QPoint position(QRect rect) { return rect.center(); }
183inline QPoint position(QRectF rect) { return rect.center().toPoint(); }
184
185template <typename T, typename C>
186T fromNativePixels(const T &value, const C *context)
187{
188 QPoint nativePosition = position(value);
189 QHighDpiScaling::ScaleAndOrigin so = QHighDpiScaling::scaleAndOrigin(context, &nativePosition);
190 return scale(value, qreal(1) / so.factor, so.origin);
191}
192
193template <typename T, typename C>
194T toNativePixels(const T &value, const C *context)
195{
196 QHighDpiScaling::ScaleAndOrigin so = QHighDpiScaling::scaleAndOrigin(context);
197 return scale(value, so.factor, so.origin);
198}
199
200template <typename T, typename C>
201T fromNativeLocalPosition(const T &value, const C *context)
202{
203 return scale(value, qreal(1) / QHighDpiScaling::factor(context));
204}
205
206template <typename T, typename C>
207T toNativeLocalPosition(const T &value, const C *context)
208{
209 return scale(value, QHighDpiScaling::factor(context));
210}
211
212template <typename T>
213inline T fromNative(const T &value, qreal scaleFactor, QPoint origin = QPoint(0, 0))
214{
215 return scale(value, qreal(1) / scaleFactor, origin);
216}
217
218template <typename T>
219inline T toNative(const T &value, qreal scaleFactor, QPoint origin = QPoint(0, 0))
220{
221 return scale(value, scaleFactor, origin);
222}
223
224inline QRect fromNative(const QRect &rect, const QScreen *screen, const QPoint &screenOrigin)
225{
226 return scale(rect, qreal(1) / QHighDpiScaling::factor(screen), screenOrigin);
227}
228
229inline QRect fromNativeScreenGeometry(const QRect &nativeScreenGeometry, const QScreen *screen)
230{
231 return QRect(nativeScreenGeometry.topLeft(),
232 scale(nativeScreenGeometry.size(), qreal(1) / QHighDpiScaling::factor(screen)));
233}
234
235inline QRegion fromNativeLocalRegion(const QRegion &pixelRegion, const QWindow *window)
236{
237 return scale(pixelRegion, qreal(1) / QHighDpiScaling::factor(window));
238}
239
240// When mapping expose events to Qt rects: round top/left towards the origin and
241// bottom/right away from the origin, making sure that we cover the whole window.
242inline QRegion fromNativeLocalExposedRegion(const QRegion &pixelRegion, const QWindow *window)
243{
244 if (!QHighDpiScaling::isActive())
245 return pixelRegion;
246
247 const qreal scaleFactor = QHighDpiScaling::factor(window);
248 QRegion pointRegion;
249 for (const QRectF &rect : pixelRegion) {
250 const QPointF topLeftP = rect.topLeft() / scaleFactor;
251 const QSizeF sizeP = rect.size() / scaleFactor;
252 pointRegion += QRect(QPoint(qFloor(topLeftP.x()), qFloor(topLeftP.y())),
253 QPoint(qCeil(topLeftP.x() + sizeP.width() - 1.0),
254 qCeil(topLeftP.y() + sizeP.height() - 1.0)));
255 }
256 return pointRegion;
257}
258
259inline QRegion toNativeLocalRegion(const QRegion &pointRegion, const QWindow *window)
260{
261 return scale(pointRegion, QHighDpiScaling::factor(window));
262}
263
264} // namespace QHighDpi
265#else // QT_NO_HIGHDPISCALING
266class Q_GUI_EXPORT QHighDpiScaling {
267public:
268 static inline void initHighDpiScaling() {}
269 static inline void updateHighDpiScaling() {}
270 static inline void setGlobalFactor(qreal) {}
271 static inline void setScreenFactor(QScreen *, qreal) {}
272
273 static inline bool isActive() { return false; }
274 static inline qreal factor(const QWindow *) { return 1.0; }
275 static inline qreal factor(const QScreen *) { return 1.0; }
276 static inline qreal factor(const QPlatformScreen *) { return 1.0; }
277 static inline QPoint origin(const QScreen *) { return QPoint(); }
278 static inline QPoint origin(const QPlatformScreen *) { return QPoint(); }
279 static inline QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *) { return pos; }
280 static inline QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *) { return pos; }
281 static inline QPoint mapPositionToGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window) { return pos; }
282 static inline QPoint mapPositionFromGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window) { return pos; }
283 static inline QDpi logicalDpi() { return QDpi(-1,-1); }
284};
285
286namespace QHighDpi {
287 template <typename T> inline
288 T toNative(const T &value, ...) { return value; }
289 template <typename T> inline
290 T fromNative(const T &value, ...) { return value; }
291
292 template <typename T> inline
293 T fromNativeLocalPosition(const T &value, ...) { return value; }
294 template <typename T> inline
295 T toNativeLocalPosition(const T &value, ...) { return value; }
296
297 template <typename T> inline
298 T fromNativeLocalRegion(const T &value, ...) { return value; }
299 template <typename T> inline
300 T fromNativeLocalExposedRegion(const T &value, ...) { return value; }
301 template <typename T> inline
302 T toNativeLocalRegion(const T &value, ...) { return value; }
303
304 template <typename T> inline
305 T fromNativeScreenGeometry(const T &value, ...) { return value; }
306
307 template <typename T, typename U> inline
308 T toNativePixels(const T &value, const U*) {return value;}
309 template <typename T, typename U> inline
310 T fromNativePixels(const T &value, const U*) {return value;}
311}
312#endif // QT_NO_HIGHDPISCALING
313QT_END_NAMESPACE
314
315#endif // QHIGHDPISCALING_P_H
316