diff options
author | Ivan Solovev <ivan.solovev@qt.io> | 2022-02-10 16:43:38 +0100 |
---|---|---|
committer | Ivan Solovev <ivan.solovev@qt.io> | 2022-02-15 17:51:33 +0100 |
commit | 60799fc14134472913af4b3ab87b6160bd46056d (patch) | |
tree | b67d0e4bc9a60913883602ba0eb60c8f35565575 /src/plugins/platforms/android | |
parent | a374d59abc415eee1866322176b7762158f48abd (diff) |
Android A11Y: Fix value rounding
QAccessibleInterface stores values as QVariants. When dealing with
double values, as a result of some calculation (for example, Slider
value update), rounding errors can be introduced.
When converting double values to QString using QVariant::toString(),
these rounding errors result in strings like
0.30000000000000004 instead of 0.3 or
2.7755575615628914e-17 instead of 0.3 - 3 * 0.1 and similar zeroes.
To fix this issue, this patch introduces a custom conversion for
floating-point values. The idea is to convert QVariant to double,
and then convert double to QString using 'f' format and a suitable
precision, determined from the UI element's minimumStepSize(), if
it has one, otherwise falling back to QString::number()'s default
(which is 6).
Task-number: QTBUG-93396
Pick-to: 6.3 6.2 5.15
Change-Id: Ia5ca7345812e39629e9c191b6d8b896a8f51de80
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
Diffstat (limited to 'src/plugins/platforms/android')
-rw-r--r-- | src/plugins/platforms/android/androidjniaccessibility.cpp | 46 |
1 files changed, 44 insertions, 2 deletions
diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp index cac106be3b..807db78ecf 100644 --- a/src/plugins/platforms/android/androidjniaccessibility.cpp +++ b/src/plugins/platforms/android/androidjniaccessibility.cpp @@ -358,8 +358,50 @@ if (!clazz) { \ QString valueStr; QAccessibleValueInterface *valueIface = iface->valueInterface(); if (valueIface) { - // TODO: fix double-to-string conversion - valueStr = valueIface->currentValue().toString(); + const QVariant valueVar = valueIface->currentValue(); + const auto type = valueVar.typeId(); + if (type == QMetaType::Double || type == QMetaType::Float) { + // QVariant's toString() formats floating-point values with + // FloatingPointShortest, which is not an accessible + // representation; nor, in many cases, is it suitable to the UI + // element whose value we're looking at. So roll our own + // A11Y-friendly conversion to string. + const double val = valueVar.toDouble(); + // Try to use minimumStepSize() to determine precision + bool stepIsValid = false; + const double step = qAbs(valueIface->minimumStepSize().toDouble(&stepIsValid)); + if (!stepIsValid || qFuzzyIsNull(step)) { + // Ignore step, use default precision + valueStr = qFuzzyIsNull(val) ? u"0"_qs : QString::number(val, 'f'); + } else { + const int precision = [](double s) { + int count = 0; + while (s < 1. && !qFuzzyCompare(s, 1.)) { + ++count; + s *= 10; + } + // If s is now 1.25, we want to show some more digits, + // but don't want to get silly with a step like 1./7; + // so only include a few extra digits. + const int stop = count + 3; + const auto fractional = [](double v) { + double whole = 0.0; + std::modf(v + 0.5, &whole); + return qAbs(v - whole); + }; + s = fractional(s); + while (count < stop && !qFuzzyIsNull(s)) { + ++count; + s = fractional(s * 10); + } + return count; + }(step); + valueStr = qFuzzyIsNull(val / step) ? u"0"_qs + : QString::number(val, 'f', precision); + } + } else { + valueStr = valueVar.toString(); + } } return valueStr; } |