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/qvector2d.h>
63 #include <QtGui/qwindow.h>
64
65 QT_BEGIN_NAMESPACE
66
67 Q_DECLARE_LOGGING_CATEGORY(lcScaling);
68
69 class QScreen;
70 class QPlatformScreen;
71 typedef QPair<qreal, qreal> QDpi;
72
73 #ifndef QT_NO_HIGHDPISCALING
74 class Q_GUI_EXPORT QHighDpiScaling {
75 Q_GADGET
76 public:
77 enum class DpiAdjustmentPolicy {
78 Unset,
79 Enabled,
80 Disabled,
81 UpOnly
82 };
83 Q_ENUM(DpiAdjustmentPolicy)
84
85 QHighDpiScaling() = delete;
86 ~QHighDpiScaling() = delete;
87 QHighDpiScaling(const QHighDpiScaling &) = delete;
88 QHighDpiScaling &operator=(const QHighDpiScaling &) = delete;
89 QHighDpiScaling(QHighDpiScaling &&) = delete;
90 QHighDpiScaling &operator=(QHighDpiScaling &&) = delete;
91
92 static void initHighDpiScaling();
93 static void updateHighDpiScaling();
94 static void setGlobalFactor(qreal factor);
95 static void setScreenFactor(QScreen *screen, qreal factor);
96
isActive()97 static bool isActive() { return m_active; }
98
99 struct ScaleAndOrigin
100 {
101 qreal factor;
102 QPoint origin;
103 };
104 static ScaleAndOrigin scaleAndOrigin(const QPlatformScreen *platformScreen, QPoint *nativePosition = nullptr);
105 static ScaleAndOrigin scaleAndOrigin(const QScreen *screen, QPoint *nativePosition = nullptr);
106 static ScaleAndOrigin scaleAndOrigin(const QWindow *platformScreen, QPoint *nativePosition = nullptr);
107
108 template<typename C>
109 static qreal factor(C *context, QPoint *nativePosition = nullptr) {
110 return scaleAndOrigin(context, nativePosition).factor;
111 }
112
113 static QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen);
114 static QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen);
115 static QPoint mapPositionToGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window);
116 static QPoint mapPositionFromGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window);
117 static QDpi logicalDpi(const QScreen *screen);
118
119 private:
120 static qreal rawScaleFactor(const QPlatformScreen *screen);
121 static qreal roundScaleFactor(qreal rawFactor);
122 static QDpi effectiveLogicalDpi(const QPlatformScreen *screen, qreal rawFactor, qreal roundedFactor);
123 static qreal screenSubfactor(const QPlatformScreen *screen);
124
125 static qreal m_factor;
126 static bool m_active;
127 static bool m_usePixelDensity;
128 static bool m_globalScalingActive;
129 static bool m_pixelDensityScalingActive;
130 static bool m_screenFactorSet;
131 static QDpi m_logicalDpi;
132 };
133
134 // Coordinate system conversion functions:
135 // QHighDpi::fromNativePixels : from physical(screen/backing) to logical pixels
136 // QHighDpi::toNativePixels : from logical to physical pixels
137
138 namespace QHighDpi {
139
140 inline qreal scale(qreal value, qreal scaleFactor, QPointF /* origin */ = QPointF(0, 0))
141 {
142 return value * scaleFactor;
143 }
144
145 inline QSize scale(const QSize &value, qreal scaleFactor, QPointF /* origin */ = QPointF(0, 0))
146 {
147 return value * scaleFactor;
148 }
149
150 inline QSizeF scale(const QSizeF &value, qreal scaleFactor, QPointF /* origin */ = QPointF(0, 0))
151 {
152 return value * scaleFactor;
153 }
154
155 inline QVector2D scale(const QVector2D &value, qreal scaleFactor, QPointF /* origin */ = QPointF(0, 0))
156 {
157 return value * float(scaleFactor);
158 }
159
160 inline QPointF scale(const QPointF &pos, qreal scaleFactor, QPointF origin = QPointF(0, 0))
161 {
162 return (pos - origin) * scaleFactor + origin;
163 }
164
165 inline QPoint scale(const QPoint &pos, qreal scaleFactor, QPoint origin = QPoint(0, 0))
166 {
167 return (pos - origin) * scaleFactor + origin;
168 }
169
170 inline QRect scale(const QRect &rect, qreal scaleFactor, QPoint origin = QPoint(0, 0))
171 {
172 return QRect(scale(rect.topLeft(), scaleFactor, origin), scale(rect.size(), scaleFactor));
173 }
174
175 inline QRectF scale(const QRectF &rect, qreal scaleFactor, QPoint origin = QPoint(0, 0))
176 {
177 return QRectF(scale(rect.topLeft(), scaleFactor, origin), scale(rect.size(), scaleFactor));
178 }
179
180 inline QMargins scale(const QMargins &margins, qreal scaleFactor, QPoint origin = QPoint(0, 0))
181 {
182 Q_UNUSED(origin)
183 return QMargins(qRound(qreal(margins.left()) * scaleFactor), qRound(qreal(margins.top()) * scaleFactor),
184 qRound(qreal(margins.right()) * scaleFactor), qRound(qreal(margins.bottom()) * scaleFactor));
185 }
186
187 template <typename T>
188 QVector<T> scale(const QVector<T> &vector, qreal scaleFactor, QPoint origin = QPoint(0, 0))
189 {
190 if (!QHighDpiScaling::isActive())
191 return vector;
192
193 QVector<T> scaled;
194 scaled.reserve(vector.size());
195 for (const T &item : vector)
196 scaled.append(scale(item, scaleFactor, origin));
197 return scaled;
198 }
199
200 inline QRegion scale(const QRegion ®ion, qreal scaleFactor, QPoint origin = QPoint(0, 0))
201 {
202 if (!QHighDpiScaling::isActive())
203 return region;
204
205 QRegion scaled;
206 for (const QRect &rect : region)
207 scaled += scale(QRectF(rect), scaleFactor, origin).toRect();
208 return scaled;
209 }
210
211 template <typename T>
position(T)212 inline QPoint position(T) { return QPoint(); }
position(QPoint point)213 inline QPoint position(QPoint point) { return point; }
position(QPointF point)214 inline QPoint position(QPointF point) { return point.toPoint(); }
position(QRect rect)215 inline QPoint position(QRect rect) { return rect.center(); }
position(QRectF rect)216 inline QPoint position(QRectF rect) { return rect.center().toPoint(); }
217
218 template <typename T, typename C>
fromNativePixels(const T & value,const C * context)219 T fromNativePixels(const T &value, const C *context)
220 {
221 QPoint nativePosition = position(value);
222 QHighDpiScaling::ScaleAndOrigin so = QHighDpiScaling::scaleAndOrigin(context, &nativePosition);
223 return scale(value, qreal(1) / so.factor, so.origin);
224 }
225
226 template <typename T, typename C>
toNativePixels(const T & value,const C * context)227 T toNativePixels(const T &value, const C *context)
228 {
229 QHighDpiScaling::ScaleAndOrigin so = QHighDpiScaling::scaleAndOrigin(context);
230 return scale(value, so.factor, so.origin);
231 }
232
233 template <typename T, typename C>
fromNativeLocalPosition(const T & value,const C * context)234 T fromNativeLocalPosition(const T &value, const C *context)
235 {
236 return scale(value, qreal(1) / QHighDpiScaling::factor(context));
237 }
238
239 template <typename T, typename C>
toNativeLocalPosition(const T & value,const C * context)240 T toNativeLocalPosition(const T &value, const C *context)
241 {
242 return scale(value, QHighDpiScaling::factor(context));
243 }
244
245 template <typename T>
246 inline T fromNative(const T &value, qreal scaleFactor, QPoint origin = QPoint(0, 0))
247 {
248 return scale(value, qreal(1) / scaleFactor, origin);
249 }
250
251 template <typename T>
252 inline T toNative(const T &value, qreal scaleFactor, QPoint origin = QPoint(0, 0))
253 {
254 return scale(value, scaleFactor, origin);
255 }
256
fromNative(const QRect & rect,const QScreen * screen,const QPoint & screenOrigin)257 inline QRect fromNative(const QRect &rect, const QScreen *screen, const QPoint &screenOrigin)
258 {
259 return scale(rect, qreal(1) / QHighDpiScaling::factor(screen), screenOrigin);
260 }
261
fromNativeScreenGeometry(const QRect & nativeScreenGeometry,const QScreen * screen)262 inline QRect fromNativeScreenGeometry(const QRect &nativeScreenGeometry, const QScreen *screen)
263 {
264 return QRect(nativeScreenGeometry.topLeft(),
265 scale(nativeScreenGeometry.size(), qreal(1) / QHighDpiScaling::factor(screen)));
266 }
267
fromNativeLocalRegion(const QRegion & pixelRegion,const QWindow * window)268 inline QRegion fromNativeLocalRegion(const QRegion &pixelRegion, const QWindow *window)
269 {
270 return scale(pixelRegion, qreal(1) / QHighDpiScaling::factor(window));
271 }
272
273 // When mapping expose events to Qt rects: round top/left towards the origin and
274 // bottom/right away from the origin, making sure that we cover the whole window.
fromNativeLocalExposedRegion(const QRegion & pixelRegion,const QWindow * window)275 inline QRegion fromNativeLocalExposedRegion(const QRegion &pixelRegion, const QWindow *window)
276 {
277 if (!QHighDpiScaling::isActive())
278 return pixelRegion;
279
280 const qreal scaleFactor = QHighDpiScaling::factor(window);
281 QRegion pointRegion;
282 for (const QRectF rect: pixelRegion) {
283 const QPointF topLeftP = rect.topLeft() / scaleFactor;
284 const QSizeF sizeP = rect.size() / scaleFactor;
285 pointRegion += QRect(QPoint(qFloor(topLeftP.x()), qFloor(topLeftP.y())),
286 QPoint(qCeil(topLeftP.x() + sizeP.width() - 1.0),
287 qCeil(topLeftP.y() + sizeP.height() - 1.0)));
288 }
289 return pointRegion;
290 }
291
toNativeLocalRegion(const QRegion & pointRegion,const QWindow * window)292 inline QRegion toNativeLocalRegion(const QRegion &pointRegion, const QWindow *window)
293 {
294 return scale(pointRegion, QHighDpiScaling::factor(window));
295 }
296
297 } // namespace QHighDpi
298 #else // QT_NO_HIGHDPISCALING
299 class Q_GUI_EXPORT QHighDpiScaling {
300 public:
initHighDpiScaling()301 static inline void initHighDpiScaling() {}
updateHighDpiScaling()302 static inline void updateHighDpiScaling() {}
setGlobalFactor(qreal)303 static inline void setGlobalFactor(qreal) {}
setScreenFactor(QScreen *,qreal)304 static inline void setScreenFactor(QScreen *, qreal) {}
305
isActive()306 static inline bool isActive() { return false; }
factor(const QWindow *)307 static inline qreal factor(const QWindow *) { return 1.0; }
factor(const QScreen *)308 static inline qreal factor(const QScreen *) { return 1.0; }
factor(const QPlatformScreen *)309 static inline qreal factor(const QPlatformScreen *) { return 1.0; }
origin(const QScreen *)310 static inline QPoint origin(const QScreen *) { return QPoint(); }
origin(const QPlatformScreen *)311 static inline QPoint origin(const QPlatformScreen *) { return QPoint(); }
mapPositionFromNative(const QPoint & pos,const QPlatformScreen *)312 static inline QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *) { return pos; }
mapPositionToNative(const QPoint & pos,const QPlatformScreen *)313 static inline QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *) { return pos; }
mapPositionToGlobal(const QPoint & pos,const QPoint & windowGlobalPosition,const QWindow * window)314 static inline QPoint mapPositionToGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window) { return pos; }
mapPositionFromGlobal(const QPoint & pos,const QPoint & windowGlobalPosition,const QWindow * window)315 static inline QPoint mapPositionFromGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window) { return pos; }
logicalDpi(const QScreen * screen)316 static inline QDpi logicalDpi(const QScreen *screen) { return QDpi(-1,-1); }
317 };
318
319 namespace QHighDpi {
320 template <typename T> inline
toNative(const T & value,...)321 T toNative(const T &value, ...) { return value; }
322 template <typename T> inline
fromNative(const T & value,...)323 T fromNative(const T &value, ...) { return value; }
324
325 template <typename T> inline
fromNativeLocalPosition(const T & value,...)326 T fromNativeLocalPosition(const T &value, ...) { return value; }
327 template <typename T> inline
toNativeLocalPosition(const T & value,...)328 T toNativeLocalPosition(const T &value, ...) { return value; }
329
330 template <typename T> inline
fromNativeLocalRegion(const T & value,...)331 T fromNativeLocalRegion(const T &value, ...) { return value; }
332 template <typename T> inline
fromNativeLocalExposedRegion(const T & value,...)333 T fromNativeLocalExposedRegion(const T &value, ...) { return value; }
334 template <typename T> inline
toNativeLocalRegion(const T & value,...)335 T toNativeLocalRegion(const T &value, ...) { return value; }
336
337 template <typename T> inline
fromNativeScreenGeometry(const T & value,...)338 T fromNativeScreenGeometry(const T &value, ...) { return value; }
339
340 template <typename T, typename U> inline
toNativePixels(const T & value,const U *)341 T toNativePixels(const T &value, const U*) {return value;}
342 template <typename T, typename U> inline
fromNativePixels(const T & value,const U *)343 T fromNativePixels(const T &value, const U*) {return value;}
344 }
345 #endif // QT_NO_HIGHDPISCALING
346 QT_END_NAMESPACE
347
348 #endif // QHIGHDPISCALING_P_H
349