diff --git a/third_party/accessibility/base/BUILD.gn b/third_party/accessibility/base/BUILD.gn index c630ba7391b59..0897fa07224b0 100644 --- a/third_party/accessibility/base/BUILD.gn +++ b/third_party/accessibility/base/BUILD.gn @@ -53,5 +53,6 @@ source_set("base") { public_deps = [ "numerics", "//flutter/third_party/accessibility/ax_build", + "//third_party/dart/runtime/third_party/double-conversion/src:libdouble_conversion", ] } diff --git a/third_party/accessibility/base/string_utils.cc b/third_party/accessibility/base/string_utils.cc index 0dff8dd88a7ee..0152bbcbef65e 100644 --- a/third_party/accessibility/base/string_utils.cc +++ b/third_party/accessibility/base/string_utils.cc @@ -4,12 +4,15 @@ #include "string_utils.h" +#include #include #include #include #include #include +#include "third_party/dart/runtime/third_party/double-conversion/src/double-conversion.h" + #if defined(_WIN32) #include "base/win/string_conversion.h" #endif @@ -18,6 +21,48 @@ namespace base { +using double_conversion::DoubleToStringConverter; +using double_conversion::StringBuilder; + +namespace { +constexpr char kExponentChar = 'e'; +constexpr char kInfinitySymbol[] = "Infinity"; +constexpr char kNaNSymbol[] = "NaN"; + +// The number of digits after the decimal we allow before switching to +// exponential representation. +constexpr int kDecimalInShortestLow = -6; +// The number of digits before the decimal we allow before switching to +// exponential representation. +constexpr int kDecimalInShortestHigh = 12; +constexpr int kConversionFlags = + DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN; + +const DoubleToStringConverter& GetDoubleToStringConverter() { + static DoubleToStringConverter converter( + kConversionFlags, kInfinitySymbol, kNaNSymbol, kExponentChar, + kDecimalInShortestLow, kDecimalInShortestHigh, 0, 0); + return converter; +} + +std::string NumberToStringImpl(double number, bool is_single_precision) { + if (number == 0.0) { + return "0"; + } + + constexpr int kBufferSize = 128; + std::array char_buffer; + StringBuilder builder(char_buffer.data(), char_buffer.size()); + if (is_single_precision) { + GetDoubleToStringConverter().ToShortestSingle(static_cast(number), + &builder); + } else { + GetDoubleToStringConverter().ToShortest(number, &builder); + } + return std::string(char_buffer.data(), builder.position()); +} +} // namespace + std::u16string ASCIIToUTF16(std::string src) { return std::u16string(src.begin(), src.end()); } @@ -73,15 +118,11 @@ std::string NumberToString(unsigned int number) { } std::string NumberToString(float number) { - // TODO(gw280): Format decimals to the shortest reasonable representation. - // See: https://github.com/flutter/flutter/issues/78460 - return std::to_string(number); + return NumberToStringImpl(number, true); } std::string NumberToString(double number) { - // TODO(gw280): Format decimals to the shortest reasonable representation. - // See: https://github.com/flutter/flutter/issues/78460 - return std::to_string(number); + return NumberToStringImpl(number, false); } std::string JoinString(std::vector tokens, std::string delimiter) { diff --git a/third_party/accessibility/base/string_utils.h b/third_party/accessibility/base/string_utils.h index ab1086c83881d..8ec5f05c245c8 100644 --- a/third_party/accessibility/base/string_utils.h +++ b/third_party/accessibility/base/string_utils.h @@ -29,9 +29,9 @@ std::string UTF16ToUTF8(std::u16string src); std::u16string WideToUTF16(const std::wstring& src); std::wstring UTF16ToWide(const std::u16string& src); -std::u16string NumberToString16(float number); std::u16string NumberToString16(unsigned int number); std::u16string NumberToString16(int32_t number); +std::u16string NumberToString16(float number); std::u16string NumberToString16(double number); std::string NumberToString(unsigned int number); diff --git a/third_party/accessibility/base/string_utils_unittest.cc b/third_party/accessibility/base/string_utils_unittest.cc index dab09ead59833..8f5d0fc3f6bb2 100644 --- a/third_party/accessibility/base/string_utils_unittest.cc +++ b/third_party/accessibility/base/string_utils_unittest.cc @@ -6,6 +6,7 @@ #include #include +#include #include "base/logging.h" #include "gtest/gtest.h" @@ -42,17 +43,38 @@ TEST(StringUtilsTest, canUTF16ToUTF8) { } TEST(StringUtilsTest, canNumberToString16) { - float number = 1.123; - EXPECT_EQ(NumberToString16(number).compare(u"1.123000"), 0); + EXPECT_EQ(NumberToString16(1.123f), std::u16string(u"1.123")); } -TEST(StringUtilsTest, canNumberToString) { - float f = 1.123; - EXPECT_EQ(NumberToString(f).compare("1.123000"), 0); - unsigned int s = 11; - EXPECT_EQ(NumberToString(s).compare("11"), 0); - int32_t i = -23; - EXPECT_EQ(NumberToString(i).compare("-23"), 0); +TEST(StringUtilsTest, numberToStringSimplifiesOutput) { + EXPECT_STREQ(NumberToString(0.0).c_str(), "0"); + EXPECT_STREQ(NumberToString(0.0f).c_str(), "0"); + EXPECT_STREQ(NumberToString(1.123).c_str(), "1.123"); + EXPECT_STREQ(NumberToString(1.123f).c_str(), "1.123"); + EXPECT_STREQ(NumberToString(-1.123).c_str(), "-1.123"); + EXPECT_STREQ(NumberToString(-1.123f).c_str(), "-1.123"); + EXPECT_STREQ(NumberToString(1.00001).c_str(), "1.00001"); + EXPECT_STREQ(NumberToString(1.00001f).c_str(), "1.00001"); + EXPECT_STREQ(NumberToString(1000.000001).c_str(), "1000.000001"); + EXPECT_STREQ(NumberToString(10.00001f).c_str(), "10.00001"); + EXPECT_STREQ(NumberToString(1.0 + 1e-8).c_str(), "1.00000001"); + EXPECT_STREQ(NumberToString(1.0f + 1e-8f).c_str(), "1"); + EXPECT_STREQ(NumberToString(1e-6).c_str(), "0.000001"); + EXPECT_STREQ(NumberToString(1e-6f).c_str(), "0.000001"); + EXPECT_STREQ(NumberToString(1e-8).c_str(), "1e-8"); + EXPECT_STREQ(NumberToString(1e-8f).c_str(), "1e-8"); + EXPECT_STREQ(NumberToString(100.0).c_str(), "100"); + EXPECT_STREQ(NumberToString(100.0f).c_str(), "100"); + EXPECT_STREQ(NumberToString(-1.0 - 1e-7).c_str(), "-1.0000001"); + EXPECT_STREQ(NumberToString(-1.0f - 1e-7f).c_str(), "-1.0000001"); + EXPECT_STREQ(NumberToString(0.00000012345678).c_str(), "1.2345678e-7"); + // Difference in output is due to differences in double and float precision. + EXPECT_STREQ(NumberToString(0.00000012345678f).c_str(), "1.2345679e-7"); + EXPECT_STREQ(NumberToString(-0.00000012345678).c_str(), "-1.2345678e-7"); + // Difference in output is due to differences in double and float precision. + EXPECT_STREQ(NumberToString(-0.00000012345678f).c_str(), "-1.2345679e-7"); + EXPECT_STREQ(NumberToString(static_cast(11)).c_str(), "11"); + EXPECT_STREQ(NumberToString(static_cast(-23)).c_str(), "-23"); } } // namespace base