The windowing system provides Qt with a per-display logical DPI value.
For Windows, the possible values are:
|DPI percentage||Registry Data||Value|
[ 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.
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) firstname.lastname@example.org (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)
- 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
- (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.
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.
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:
Can we possibly use config values from the desktop?
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.