Add high-DPI scale factor rounding policy C++ API

This API enables tuning of how Qt rounds fractional scale factors, and
corresponds to the QT_SCALE_FACTOR_ROUNDING_POLICY environment
variable

New API:
	Qt::HighDPiScaleFactorRoundingPolicy
	QGuiApplication::setHighDpiScaleFactorRoundingPolicy()
	QGuiApplication::highDpiScaleFactorRoundingPolicy()

Done-with: Friedemann Kleint <Friedemann.Kleint@qt.io>
Task-number: QTBUG-53022
Change-Id: Ic360f26a173caa757e4ebde35ce08a6b74290b7d
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
This commit is contained in:
Morten Johan Sørvig 2017-10-07 01:35:29 +02:00
parent 1de8b01d2b
commit f1e40dd6d6
7 changed files with 106 additions and 31 deletions

View File

@ -1754,6 +1754,15 @@ public:
ChecksumItuV41
};
enum class HighDpiScaleFactorRoundingPolicy {
Unset,
Round,
Ceil,
Floor,
RoundPreferFloor,
PassThrough
};
#ifndef Q_QDOC
// NOTE: Generally, do not add QT_Q_ENUM if a corresponding Q_Q_FLAG exists.
QT_Q_ENUM(ScrollBarPolicy)
@ -1840,6 +1849,7 @@ public:
QT_Q_ENUM(MouseEventSource)
QT_Q_FLAG(MouseEventFlag)
QT_Q_ENUM(ChecksumType)
QT_Q_ENUM(HighDpiScaleFactorRoundingPolicy)
QT_Q_ENUM(TabFocusBehavior)
#endif // Q_DOC

View File

@ -3275,3 +3275,25 @@
\value ChecksumItuV41 Checksum calculation based on ITU-V.41.
*/
/*!
\enum Qt::HighDpiScaleFactorRoundingPolicy
\since 5.14
This enum describes the possible High-DPI scale factor rounding policies, which
decide how non-integer scale factors (such as Windows 150%) are handled.
The active policy is set by calling QGuiApplication::setHighDdpiScaleFactorRoundingPolicy() before
the application object is created, or by setting the QT_SCALE_FACTOR_ROUNDING_POLICY
environment variable.
\sa QGuiApplication::setHighDdpiScaleFactorRoundingPolicy()
\sa AA_EnableHighDpiScaling.
\omitvalue Unset
\value Round Round up for .5 and above.
\value Ceil Always round up.
\value Floor Always round down.
\value RoundPreferFloor Round up for .75 and above.
\value PassThrough Don't round.
*/

View File

@ -146,6 +146,8 @@ QString QGuiApplicationPrivate::styleOverride;
Qt::ApplicationState QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive;
Qt::HighDpiScaleFactorRoundingPolicy QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy =
Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor;
bool QGuiApplicationPrivate::highDpiScalingUpdated = false;
QPointer<QWindow> QGuiApplicationPrivate::currentDragWindow;
@ -687,6 +689,8 @@ QGuiApplication::~QGuiApplication()
QGuiApplicationPrivate::lastCursorPosition = {qInf(), qInf()};
QGuiApplicationPrivate::currentMousePressWindow = QGuiApplicationPrivate::currentMouseWindow = nullptr;
QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive;
QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy =
Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor;
QGuiApplicationPrivate::highDpiScalingUpdated = false;
QGuiApplicationPrivate::currentDragWindow = nullptr;
QGuiApplicationPrivate::tabletDevicePoints.clear();
@ -3490,6 +3494,46 @@ Qt::ApplicationState QGuiApplication::applicationState()
return QGuiApplicationPrivate::applicationState;
}
/*!
\since 5.14
Sets the high-DPI scale factor rounding policy for the application. The
policy decides how non-integer scale factors (such as Windows 150%) are
handled, for applications that have AA_EnableHighDpiScaling enabled.
The two principal options are whether fractional scale factors should
be rounded to an integer or not. Keeping the scale factor as-is will
make the user interface size match the OS setting exactly, but may cause
painting errors, for example with the Windows style.
If rounding is wanted, then which type of rounding should be decided
next. Mathematically correct rounding is supported but may not give
the best visual results: Consider if you want to render 1.5x as 1x
("small UI") or as 2x ("large UI"). See the Qt::HighDpiScaleFactorRoundingPolicy
enum for a complete list of all options.
This function must be called before creating the application object,
and can be overridden by setting the QT_SCALE_FACTOR_ROUNDING_POLICY
environment variable. The QGuiApplication::highDpiScaleFactorRoundingPolicy()
accessor will reflect the environment, if set.
The default value is Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor.
*/
void QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy policy)
{
QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy = policy;
}
/*!
\since 5.14
Returns the high-DPI scale factor rounding policy.
*/
Qt::HighDpiScaleFactorRoundingPolicy QGuiApplication::highDpiScaleFactorRoundingPolicy()
{
return QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy;
}
/*!
\since 5.2
\fn void QGuiApplication::applicationStateChanged(Qt::ApplicationState state)

View File

@ -156,6 +156,9 @@ public:
static Qt::ApplicationState applicationState();
static void setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy policy);
static Qt::HighDpiScaleFactorRoundingPolicy highDpiScaleFactorRoundingPolicy();
static int exec();
bool notify(QObject *, QEvent *) override;

View File

@ -223,6 +223,7 @@ public:
static QWindow *currentMouseWindow;
static QWindow *currentMousePressWindow;
static Qt::ApplicationState applicationState;
static Qt::HighDpiScaleFactorRoundingPolicy highDpiScaleFactorRoundingPolicy;
static bool highDpiScalingUpdated;
static QPointer<QWindow> currentDragWindow;

View File

@ -331,24 +331,24 @@ static QByteArray joinEnumValues(const EnumLookup<EnumType> *i1, const EnumLooku
return result;
}
using ScaleFactorRoundingPolicyLookup = EnumLookup<QHighDpiScaling::HighDpiScaleFactorRoundingPolicy>;
using ScaleFactorRoundingPolicyLookup = EnumLookup<Qt::HighDpiScaleFactorRoundingPolicy>;
static const ScaleFactorRoundingPolicyLookup scaleFactorRoundingPolicyLookup[] =
{
{"Round", QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::Round},
{"Ceil", QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::Ceil},
{"Floor", QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::Floor},
{"RoundPreferFloor", QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor},
{"PassThrough", QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::PassThrough}
{"Round", Qt::HighDpiScaleFactorRoundingPolicy::Round},
{"Ceil", Qt::HighDpiScaleFactorRoundingPolicy::Ceil},
{"Floor", Qt::HighDpiScaleFactorRoundingPolicy::Floor},
{"RoundPreferFloor", Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor},
{"PassThrough", Qt::HighDpiScaleFactorRoundingPolicy::PassThrough}
};
static QHighDpiScaling::HighDpiScaleFactorRoundingPolicy
static Qt::HighDpiScaleFactorRoundingPolicy
lookupScaleFactorRoundingPolicy(const QByteArray &v)
{
auto end = std::end(scaleFactorRoundingPolicyLookup);
auto it = std::find(std::begin(scaleFactorRoundingPolicyLookup), end,
ScaleFactorRoundingPolicyLookup{v.constData(), QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::Unset});
return it != end ? it->value : QHighDpiScaling::HighDpiScaleFactorRoundingPolicy::Unset;
ScaleFactorRoundingPolicyLookup{v.constData(), Qt::HighDpiScaleFactorRoundingPolicy::Unset});
return it != end ? it->value : Qt::HighDpiScaleFactorRoundingPolicy::Unset;
}
using DpiAdjustmentPolicyLookup = EnumLookup<QHighDpiScaling::DpiAdjustmentPolicy>;
@ -377,15 +377,15 @@ qreal QHighDpiScaling::roundScaleFactor(qreal rawFactor)
// sizes that are smaller than the ideal size, and opposite for rounding up.
// Rounding down is then preferable since "small UI" is a more acceptable
// high-DPI experience than "large UI".
static auto scaleFactorRoundingPolicy = HighDpiScaleFactorRoundingPolicy::Unset;
static auto scaleFactorRoundingPolicy = Qt::HighDpiScaleFactorRoundingPolicy::Unset;
// Determine rounding policy
if (scaleFactorRoundingPolicy == HighDpiScaleFactorRoundingPolicy::Unset) {
if (scaleFactorRoundingPolicy == Qt::HighDpiScaleFactorRoundingPolicy::Unset) {
// Check environment
if (qEnvironmentVariableIsSet(scaleFactorRoundingPolicyEnvVar)) {
QByteArray policyText = qgetenv(scaleFactorRoundingPolicyEnvVar);
auto policyEnumValue = lookupScaleFactorRoundingPolicy(policyText);
if (policyEnumValue != HighDpiScaleFactorRoundingPolicy::Unset) {
if (policyEnumValue != Qt::HighDpiScaleFactorRoundingPolicy::Unset) {
scaleFactorRoundingPolicy = policyEnumValue;
} else {
auto values = joinEnumValues(std::begin(scaleFactorRoundingPolicyLookup),
@ -393,38 +393,43 @@ qreal QHighDpiScaling::roundScaleFactor(qreal rawFactor)
qWarning("Unknown scale factor rounding policy: %s. Supported values are: %s.",
policyText.constData(), values.constData());
}
}
// Check application object if no environment value was set.
if (scaleFactorRoundingPolicy == Qt::HighDpiScaleFactorRoundingPolicy::Unset) {
scaleFactorRoundingPolicy = QGuiApplication::highDpiScaleFactorRoundingPolicy();
} else {
// Set default policy if no environment variable is set.
scaleFactorRoundingPolicy = HighDpiScaleFactorRoundingPolicy::RoundPreferFloor;
// Make application setting reflect environment
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(scaleFactorRoundingPolicy);
}
}
// Apply rounding policy.
qreal roundedFactor = rawFactor;
switch (scaleFactorRoundingPolicy) {
case HighDpiScaleFactorRoundingPolicy::Round:
case Qt::HighDpiScaleFactorRoundingPolicy::Round:
roundedFactor = qRound(rawFactor);
break;
case HighDpiScaleFactorRoundingPolicy::Ceil:
case Qt::HighDpiScaleFactorRoundingPolicy::Ceil:
roundedFactor = qCeil(rawFactor);
break;
case HighDpiScaleFactorRoundingPolicy::Floor:
case Qt::HighDpiScaleFactorRoundingPolicy::Floor:
roundedFactor = qFloor(rawFactor);
break;
case HighDpiScaleFactorRoundingPolicy::RoundPreferFloor:
case Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor:
// Round up for .75 and higher. This favors "small UI" over "large UI".
roundedFactor = rawFactor - qFloor(rawFactor) < 0.75
? qFloor(rawFactor) : qCeil(rawFactor);
break;
case HighDpiScaleFactorRoundingPolicy::PassThrough:
case HighDpiScaleFactorRoundingPolicy::Unset:
case Qt::HighDpiScaleFactorRoundingPolicy::PassThrough:
case Qt::HighDpiScaleFactorRoundingPolicy::Unset:
break;
}
// Don't round down to to zero; clamp the minimum (rounded) factor to 1.
// This is not a common case but can happen if a display reports a very
// low DPI.
if (scaleFactorRoundingPolicy != HighDpiScaleFactorRoundingPolicy::PassThrough)
if (scaleFactorRoundingPolicy != Qt::HighDpiScaleFactorRoundingPolicy::PassThrough)
roundedFactor = qMax(roundedFactor, qreal(1));
return roundedFactor;

View File

@ -74,16 +74,6 @@ typedef QPair<qreal, qreal> QDpi;
class Q_GUI_EXPORT QHighDpiScaling {
Q_GADGET
public:
enum class HighDpiScaleFactorRoundingPolicy {
Unset,
Round,
Ceil,
Floor,
RoundPreferFloor,
PassThrough
};
Q_ENUM(HighDpiScaleFactorRoundingPolicy)
enum class DpiAdjustmentPolicy {
Unset,
Enabled,