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 &region, 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