1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QHIGHDPISCALING_P_H
5#define QHIGHDPISCALING_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtGui/private/qtguiglobal_p.h>
19#include <QtCore/qlist.h>
20#include <QtCore/qloggingcategory.h>
21#include <QtCore/qmargins.h>
22#include <QtCore/qmath.h>
23#include <QtCore/qrect.h>
24#include <QtGui/qregion.h>
25#include <QtGui/qscreen.h>
26#include <QtGui/qvector2d.h>
27#include <QtGui/qwindow.h>
28
29QT_BEGIN_NAMESPACE
30
31Q_DECLARE_LOGGING_CATEGORY(lcHighDpi);
32
33class QScreen;
34class QPlatformScreen;
35typedef QPair<qreal, qreal> QDpi;
36
37#ifndef QT_NO_HIGHDPISCALING
38class Q_GUI_EXPORT QHighDpiScaling {
39 Q_GADGET
40public:
41 enum class DpiAdjustmentPolicy {
42 Unset,
43 Enabled,
44 Disabled,
45 UpOnly
46 };
47 Q_ENUM(DpiAdjustmentPolicy)
48
49 QHighDpiScaling() = delete;
50 ~QHighDpiScaling() = delete;
51 QHighDpiScaling(const QHighDpiScaling &) = delete;
52 QHighDpiScaling &operator=(const QHighDpiScaling &) = delete;
53 QHighDpiScaling(QHighDpiScaling &&) = delete;
54 QHighDpiScaling &operator=(QHighDpiScaling &&) = delete;
55
56 static void initHighDpiScaling();
57 static void updateHighDpiScaling();
58 static void setGlobalFactor(qreal factor);
59 static void setScreenFactor(QScreen *screen, qreal factor);
60
61 static bool isActive() { return m_active; }
62
63 struct Point {
64 enum Kind {
65 Invalid,
66 DeviceIndependent,
67 Native
68 };
69 Kind kind;
70 QPoint point;
71 };
72
73 struct ScaleAndOrigin
74 {
75 qreal factor;
76 QPoint origin;
77 };
78
79 static ScaleAndOrigin scaleAndOrigin(const QPlatformScreen *platformScreen, Point position = Point{ .kind: Point::Invalid, .point: QPoint() });
80 static ScaleAndOrigin scaleAndOrigin(const QScreen *screen, Point position = Point{ .kind: Point::Invalid, .point: QPoint() });
81 static ScaleAndOrigin scaleAndOrigin(const QWindow *platformScreen, Point position = Point{ .kind: Point::Invalid, .point: QPoint() });
82
83 template<typename C>
84 static qreal factor(C *context) {
85 return scaleAndOrigin(context).factor;
86 }
87
88 static QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen);
89 static QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen);
90 static QDpi logicalDpi(const QScreen *screen);
91 static qreal roundScaleFactor(qreal rawFactor);
92
93private:
94 struct ScreenFactor {
95 ScreenFactor(QString name, qreal factor)
96 :name(name), factor(factor) { }
97 QString name;
98 qreal factor;
99 };
100
101 static qreal rawScaleFactor(const QPlatformScreen *screen);
102 static QDpi effectiveLogicalDpi(const QPlatformScreen *screen, qreal rawFactor, qreal roundedFactor);
103 static qreal screenSubfactor(const QPlatformScreen *screen);
104 static QScreen *screenForPosition(Point position, QScreen *guess);
105 static QVector<QHighDpiScaling::ScreenFactor> parseScreenScaleFactorsSpec(const QStringView &screenScaleFactors);
106
107 static qreal m_factor;
108 static bool m_active;
109 static bool m_usePlatformPluginDpi;
110 static bool m_platformPluginDpiScalingActive;
111 static bool m_globalScalingActive;
112 static bool m_screenFactorSet;
113 static bool m_usePhysicalDpi;
114 static QVector<ScreenFactor> m_screenFactors;
115 static DpiAdjustmentPolicy m_dpiAdjustmentPolicy;
116 static QHash<QString, qreal> m_namedScreenScaleFactors;
117
118#ifndef QT_NO_DEBUG_STREAM
119 friend Q_GUI_EXPORT QDebug operator<<(QDebug, const ScreenFactor &);
120#endif
121};
122
123namespace QHighDpi {
124
125inline qreal scale(qreal value, qreal scaleFactor, QPointF /* origin */ = QPointF(0, 0))
126{
127 return value * scaleFactor;
128}
129
130inline QSize scale(const QSize &value, qreal scaleFactor, QPointF /* origin */ = QPointF(0, 0))
131{
132 return value * scaleFactor;
133}
134
135inline QSizeF scale(const QSizeF &value, qreal scaleFactor, QPointF /* origin */ = QPointF(0, 0))
136{
137 return value * scaleFactor;
138}
139
140inline QVector2D scale(const QVector2D &value, qreal scaleFactor, QPointF /* origin */ = QPointF(0, 0))
141{
142 return value * float(scaleFactor);
143}
144
145inline QPointF scale(const QPointF &pos, qreal scaleFactor, QPointF origin = QPointF(0, 0))
146{
147 return (pos - origin) * scaleFactor + origin;
148}
149
150inline QPoint scale(const QPoint &pos, qreal scaleFactor, QPoint origin = QPoint(0, 0))
151{
152 return (pos - origin) * scaleFactor + origin;
153}
154
155inline QRect scale(const QRect &rect, qreal scaleFactor, QPoint origin = QPoint(0, 0))
156{
157 return QRect(scale(pos: rect.topLeft(), scaleFactor, origin), scale(value: rect.size(), scaleFactor));
158}
159
160inline QRectF scale(const QRectF &rect, qreal scaleFactor, QPoint origin = QPoint(0, 0))
161{
162 return QRectF(scale(pos: rect.topLeft(), scaleFactor, origin), scale(value: rect.size(), scaleFactor));
163}
164
165inline QMargins scale(const QMargins &margins, qreal scaleFactor, QPoint origin = QPoint(0, 0))
166{
167 Q_UNUSED(origin);
168 return QMargins(qRound(d: qreal(margins.left()) * scaleFactor), qRound(d: qreal(margins.top()) * scaleFactor),
169 qRound(d: qreal(margins.right()) * scaleFactor), qRound(d: qreal(margins.bottom()) * scaleFactor));
170}
171
172template<typename T>
173QList<T> scale(const QList<T> &list, qreal scaleFactor, QPoint origin = QPoint(0, 0))
174{
175 if (!QHighDpiScaling::isActive())
176 return list;
177
178 QList<T> scaled;
179 scaled.reserve(list.size());
180 for (const T &item : list)
181 scaled.append(scale(item, scaleFactor, origin));
182 return scaled;
183}
184
185inline QRegion scale(const QRegion &region, qreal scaleFactor, QPoint origin = QPoint(0, 0))
186{
187 if (!QHighDpiScaling::isActive())
188 return region;
189
190 QRegion scaled = region.translated(p: -origin);
191 scaled = QTransform::fromScale(dx: scaleFactor, dy: scaleFactor).map(r: scaled);
192 return scaled.translated(p: origin);
193}
194
195template <typename T>
196inline QHighDpiScaling::Point position(T, QHighDpiScaling::Point::Kind) {
197 return QHighDpiScaling::Point{ .kind: QHighDpiScaling::Point::Invalid, .point: QPoint() };
198}
199inline QHighDpiScaling::Point position(QPoint point, QHighDpiScaling::Point::Kind kind) {
200 return QHighDpiScaling::Point{ .kind: kind, .point: point };
201}
202inline QHighDpiScaling::Point position(QPointF point, QHighDpiScaling::Point::Kind kind) {
203 return QHighDpiScaling::Point{ .kind: kind, .point: point.toPoint() };
204}
205inline QHighDpiScaling::Point position(QRect rect, QHighDpiScaling::Point::Kind kind) {
206 return QHighDpiScaling::Point{ .kind: kind, .point: rect.topLeft() };
207}
208inline QHighDpiScaling::Point position(QRectF rect, QHighDpiScaling::Point::Kind kind) {
209 return QHighDpiScaling::Point{ .kind: kind, .point: rect.topLeft().toPoint() };
210}
211
212template <typename T, typename C>
213T fromNativePixels(const T &value, const C *context)
214{
215 QHighDpiScaling::ScaleAndOrigin so = QHighDpiScaling::scaleAndOrigin(context);
216 return scale(value, qreal(1) / so.factor, so.origin);
217}
218
219template <typename T, typename C>
220T toNativePixels(const T &value, const C *context)
221{
222 QHighDpiScaling::ScaleAndOrigin so = QHighDpiScaling::scaleAndOrigin(context);
223 return scale(value, so.factor, so.origin);
224}
225
226template <typename T, typename C>
227T fromNativeLocalPosition(const T &value, const C *context)
228{
229 return scale(value, qreal(1) / QHighDpiScaling::factor(context));
230}
231
232template <typename T, typename C>
233T toNativeLocalPosition(const T &value, const C *context)
234{
235 return scale(value, QHighDpiScaling::factor(context));
236}
237
238template <typename T, typename C>
239T fromNativeGlobalPosition(const T &value, const C *context)
240{
241 QHighDpiScaling::ScaleAndOrigin so =
242 QHighDpiScaling::scaleAndOrigin(context, position(value, QHighDpiScaling::Point::Native));
243 return scale(value, qreal(1) / so.factor, so.origin);
244}
245
246template <typename T, typename C>
247T toNativeGlobalPosition(const T &value, const C *context)
248{
249 QHighDpiScaling::ScaleAndOrigin so =
250 QHighDpiScaling::scaleAndOrigin(context, position(value, QHighDpiScaling::Point::DeviceIndependent));
251 return scale(value, so.factor, so.origin);
252}
253
254template <typename T, typename C>
255T fromNativeWindowGeometry(const T &value, const C *context)
256{
257 QHighDpiScaling::ScaleAndOrigin so = QHighDpiScaling::scaleAndOrigin(context);
258 QPoint effectiveOrigin = (context && context->isTopLevel()) ? so.origin : QPoint(0,0);
259 return scale(value, qreal(1) / so.factor, effectiveOrigin);
260}
261
262template <typename T, typename C>
263T toNativeWindowGeometry(const T &value, const C *context)
264{
265 QHighDpiScaling::ScaleAndOrigin so = QHighDpiScaling::scaleAndOrigin(context);
266 QPoint effectiveOrigin = (context && context->isTopLevel()) ? so.origin : QPoint(0,0);
267 return scale(value, so.factor, effectiveOrigin);
268}
269
270template <typename T>
271inline T fromNative(const T &value, qreal scaleFactor, QPoint origin = QPoint(0, 0))
272{
273 return scale(value, qreal(1) / scaleFactor, origin);
274}
275
276template <typename T>
277inline T toNative(const T &value, qreal scaleFactor, QPoint origin = QPoint(0, 0))
278{
279 return scale(value, scaleFactor, origin);
280}
281
282inline QRect fromNative(const QRect &rect, const QScreen *screen, const QPoint &screenOrigin)
283{
284 return scale(rect, scaleFactor: qreal(1) / QHighDpiScaling::factor(context: screen), origin: screenOrigin);
285}
286
287inline QRect fromNativeScreenGeometry(const QRect &nativeScreenGeometry, const QScreen *screen)
288{
289 return QRect(nativeScreenGeometry.topLeft(),
290 scale(value: nativeScreenGeometry.size(), scaleFactor: qreal(1) / QHighDpiScaling::factor(context: screen)));
291}
292
293inline QRegion fromNativeLocalRegion(const QRegion &pixelRegion, const QWindow *window)
294{
295 return scale(region: pixelRegion, scaleFactor: qreal(1) / QHighDpiScaling::factor(context: window));
296}
297
298// When mapping expose events to Qt rects: round top/left towards the origin and
299// bottom/right away from the origin, making sure that we cover the whole window.
300inline QRegion fromNativeLocalExposedRegion(const QRegion &pixelRegion, const QWindow *window)
301{
302 if (!QHighDpiScaling::isActive())
303 return pixelRegion;
304
305 const qreal scaleFactor = QHighDpiScaling::factor(context: window);
306 QRegion pointRegion;
307 for (const QRectF rect: pixelRegion)
308 pointRegion += QRectF(rect.topLeft() / scaleFactor, rect.size() / scaleFactor).toAlignedRect();
309
310 return pointRegion;
311}
312
313inline QRegion toNativeLocalRegion(const QRegion &pointRegion, const QWindow *window)
314{
315 return scale(region: pointRegion, scaleFactor: QHighDpiScaling::factor(context: window));
316}
317
318} // namespace QHighDpi
319#else // QT_NO_HIGHDPISCALING
320class Q_GUI_EXPORT QHighDpiScaling {
321public:
322 static inline void initHighDpiScaling() {}
323 static inline void updateHighDpiScaling() {}
324 static inline void setGlobalFactor(qreal) {}
325 static inline void setScreenFactor(QScreen *, qreal) {}
326
327 struct ScaleAndOrigin
328 {
329 qreal factor;
330 QPoint origin;
331 };
332 static ScaleAndOrigin scaleAndOrigin(const QPlatformScreen *platformScreen, QPoint *nativePosition = nullptr);
333 static ScaleAndOrigin scaleAndOrigin(const QScreen *screen, QPoint *nativePosition = nullptr);
334 static ScaleAndOrigin scaleAndOrigin(const QWindow *platformScreen, QPoint *nativePosition = nullptr);
335
336 static inline bool isActive() { return false; }
337 static inline qreal factor(const QWindow *) { return 1.0; }
338 static inline qreal factor(const QScreen *) { return 1.0; }
339 static inline qreal factor(const QPlatformScreen *) { return 1.0; }
340 static inline QPoint origin(const QScreen *) { return QPoint(); }
341 static inline QPoint origin(const QPlatformScreen *) { return QPoint(); }
342 static inline QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *) { return pos; }
343 static inline QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *) { return pos; }
344 static inline QPointF mapPositionToGlobal(const QPointF &pos, const QPoint &, const QWindow *) { return pos; }
345 static inline QPointF mapPositionFromGlobal(const QPointF &pos, const QPoint &, const QWindow *) { return pos; }
346 static inline QDpi logicalDpi(const QScreen *) { return QDpi(-1,-1); }
347};
348
349namespace QHighDpi {
350 template <typename T> inline
351 T scale(const T &value, ...) { return value; }
352
353 template <typename T> inline
354 T toNative(const T &value, ...) { return value; }
355 template <typename T> inline
356 T fromNative(const T &value, ...) { return value; }
357
358 template <typename T> inline
359 T fromNativeLocalPosition(const T &value, ...) { return value; }
360 template <typename T> inline
361 T toNativeLocalPosition(const T &value, ...) { return value; }
362 template <typename T, typename C> inline
363 T fromNativeGlobalPosition(const T &value, const C *) { return value; }
364 template <typename T, typename C> inline
365 T toNativeGlobalPosition(const T &value, const C *) { return value; }
366 template <typename T, typename C> inline
367 T fromNativeWindowGeometry(const T &value, const C *) { return value; }
368 template <typename T, typename C> inline
369 T toNativeWindowGeometry(const T &value, const C *) { return value; }
370
371 template <typename T> inline
372 T fromNativeLocalRegion(const T &value, ...) { return value; }
373 template <typename T> inline
374 T fromNativeLocalExposedRegion(const T &value, ...) { return value; }
375 template <typename T> inline
376 T toNativeLocalRegion(const T &value, ...) { return value; }
377
378 template <typename T> inline
379 T fromNativeScreenGeometry(const T &value, ...) { return value; }
380
381 template <typename T, typename U> inline
382 T toNativePixels(const T &value, const U*) {return value;}
383 template <typename T, typename U> inline
384 T fromNativePixels(const T &value, const U*) {return value;}
385}
386#endif // QT_NO_HIGHDPISCALING
387QT_END_NAMESPACE
388
389#endif // QHIGHDPISCALING_P_H
390

source code of qtbase/src/gui/kernel/qhighdpiscaling_p.h