Details
-
Task
-
Resolution: Done
-
P2: Important
-
None
Description
Introduction
The windowing system provides Qt with a per-display logical DPI value.
For Windows, the possible values are:
DPI percentage | Registry Data | Value |
---|---|---|
Smaller | 100% | 96 |
Medium | 125% | 120 |
Larger | 150% | 144 |
Extra Large | 200% | 192 |
Custom | 250% | 240 |
Custom | 300% | 288 |
Custom | 400% | 384 |
[ Physical DPI should not be used, since display data is unreliable and does not respect user settings ]
The 100% DPI is the base DPI. The ratio between the actual DPI and the base DPI is the scale factor, aka devicePixelRatio.
By default Qt reports the logical DPI via accessors such as QScreen::logicalDpi(), which applications can use to scale the UI. Fonts are automatically scaled. Historically the problem with this has been that not all UI elements respect the DPI.
In addition Qt supports a mode (AA_EnableHighDpiScaling) where the entire UI is automatically scaled. The logicalDpi accessors then returns the base DPI in order to avoid duplicate scaling. The devicePixelRatio() accessors returns the UI scale factor, but unlike the “classic” mode these are much less used since the scaling is automatic.
Example: For 200% (192 DPI) scaling on Windows we can configure Qt in one of two modes:
1) 192@1x (default)
2) 96@2x (AA_EnableHighDpiScaling)
So far so good.
Handling Fractional Scale Factors (like 250%)
Fractional scale factors pose a challenge since Qt may not render correctly. One option is then to round the scale factor. When rounding we also have the option of adjusting the logical DPI (as reported to the app) to compensate for the rounding error.
Rounding: We may round down or round up. The former gives visually small UI elements while the latter gives visually large UI elements. Qt currently rounds using qRound(), which for critical values like 250% means ‘up’. We should consider rounding down instead for .5.
DPI: We can fix the DPI to be the base DPI or compensate for the inaccurate scale factor. The former makes the text size match the rest of the application UI, while the latter gives correct text size for the display. We should consider at least not rounding down here (don't present DPI values below the base DPI).
Combined table of options for handling 250%: (AA_EnableHighDpiScaling mode only)
1) 96@2.5x (correct UI and text size, maybe painting artifacts)
2) 120@2x (small UI with larger text)
3) 96@2x (small UI with matching text)
4) 80@3x (large UI with smaller text) (5.6 behavor)
5) 96@3x (large UI with matching text)
QPA and QHighDpiScaling API
Current Behavior
- the platform screen provides the logical dpi
- the platform screen provides the scale factor: qRound(logical-dpi / base-dpi)
- qhighdpiscaling recovers the base-dpi by computing logical-dpi / scale factor.
- qhighdpiscaling provides QScreen::logicalDpi(), which the base dpi for the main screen
Suggested Changes:
- (the platform screen continues to provide the logical dpi)
- the platform screen provides the base-dpi instead of the scale factor
- qhighdpiscaling computes the scale factor
- qhighdpiscaling provides per-screen DPI for QScreen::logicalDpi().
- round .5 scale factors down
- perhaps compensate for rounding by increasing the reported logical DPI.
Code (gerrit)
https://codereview.qt-project.org/#/c/157173/
https://codereview.qt-project.org/#/c/157174/
https://codereview.qt-project.org/#/c/157175/
Data Flow overview
https://docs.google.com/drawings/d/1mnfCEwAL5Oo-xq4PbGwgofHq_t3Xm3xDguWNc_-YxzM
New user interface (environment variables)
Control how the scale factor is computed:
QT_SCALE_FACTOR_ROUNDING_POLICY: Round, Ceil, Floor, RoundPreferFloor, PassThrough
Control DPI adjustment:
QT_DPI_ADJUSTMENT_POLICY: AdjustDpi, DontAdjustDpi, AdjustUpOnly
tests/manual/highdpi has been updated with "--metrics" tests that displays the DPI and devicePixelRatio values.
Platform Changes
Windows: Windows already uses the logical DPI and can be trivially ported over from pixelDensity() to logicalBaseDpi().
X11: Use logical DPI instead of physical DPI. QT_FONT_DPI is now respected:
QT_FONT_DPI=160 QT_AUTO_SCREEN_SCALE_FACTOR=1./highdpi --metrics
Can we possibly use config values from the desktop?
GDK_SCALE=0.5 GDK_DPI_SCALE=0.5 org.gnome.desktop.interface scaling-factor org.gnome.desktop.interface text-scaling-factor
Android The Android base DPI is 160, but QAndroidPlatformScreen::logicalDpi() computes the logical DPI values as density * 72. This might be throwing our scale factor calculations off. Implementing QAndroidPlatformScreen::logicalBaseDpi() and making it return 72 should correct this.
Attachments
Issue Links
- is duplicated by
-
QTCREATORBUG-16293 Support of DPI Scaling Level for Displays in Windows 10
- Reported
-
QTBUG-62782 Windows: Web Engine does not support fractional scaling level
- Closed
- relates to
-
QTBUG-53500 Screen information not correctly updated when resolution changes
- Closed
-
QTBUG-45055 Widget Styles: Per-Monitor DPI Aware inconsistency
- Closed
-
QTBUG-49465 QPaintDevice::devicePixelRatioF() does not correctly return non integer ratio
- Closed
-
QTBUG-62914 Windows: High DPI scaling is rounded to nearest integer
- Closed
-
QTBUG-55654 High DPI scaling not working correctly
- Closed
-
QTBUG-73001 [Win][HiDPI][Regression 5.12.0] global positions are incorrect
- Closed
-
QTBUG-73231 When a menubar spans across displays using different DPIs then opening menus on either display can show the menu in the wrong place
- Closed