diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index f6e945d6632..651d1ae597f 100755 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -1596,6 +1596,8 @@ FILE: ../../../flutter/third_party/accessibility/base/simple_token.h FILE: ../../../flutter/third_party/accessibility/base/string_utils.cc FILE: ../../../flutter/third_party/accessibility/base/string_utils.h FILE: ../../../flutter/third_party/accessibility/base/string_utils_unittest.cc +FILE: ../../../flutter/third_party/accessibility/base/win/string_conversion.cc +FILE: ../../../flutter/third_party/accessibility/base/win/string_conversion.h FILE: ../../../flutter/third_party/accessibility/gfx/transform.cc FILE: ../../../flutter/third_party/accessibility/gfx/transform.h FILE: ../../../flutter/third_party/tonic/common/build_config.h diff --git a/engine/src/flutter/third_party/accessibility/base/BUILD.gn b/engine/src/flutter/third_party/accessibility/base/BUILD.gn index 2b4124a4aaf..c709dae8501 100644 --- a/engine/src/flutter/third_party/accessibility/base/BUILD.gn +++ b/engine/src/flutter/third_party/accessibility/base/BUILD.gn @@ -23,8 +23,10 @@ source_set("base") { "string_utils.h", ] if (is_win) { - # TODO: codecvt_utf8_utf16 is deprecated in C++17 - defines = [ "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS" ] + sources += [ + "win/string_conversion.cc", + "win/string_conversion.h", + ] } if (is_mac) { sources += [ diff --git a/engine/src/flutter/third_party/accessibility/base/string_utils.cc b/engine/src/flutter/third_party/accessibility/base/string_utils.cc index 6db165ce3dc..0dff8dd88a7 100644 --- a/engine/src/flutter/third_party/accessibility/base/string_utils.cc +++ b/engine/src/flutter/third_party/accessibility/base/string_utils.cc @@ -10,6 +10,10 @@ #include #include +#if defined(_WIN32) +#include "base/win/string_conversion.h" +#endif + #include "no_destructor.h" namespace base { @@ -19,19 +23,47 @@ std::u16string ASCIIToUTF16(std::string src) { } std::u16string UTF8ToUTF16(std::string src) { +#if defined(_WIN32) + return WideToUTF16(win::Utf16FromUtf8(src)); +#else std::wstring_convert, char16_t> convert; return convert.from_bytes(src); +#endif } std::string UTF16ToUTF8(std::u16string src) { +#if defined(_WIN32) + return win::Utf8FromUtf16(UTF16ToWide(src)); +#else std::wstring_convert, char16_t> convert; return convert.to_bytes(src); +#endif +} + +std::u16string WideToUTF16(const std::wstring& src) { + return std::u16string(src.begin(), src.end()); +} + +std::wstring UTF16ToWide(const std::u16string& src) { + return std::wstring(src.begin(), src.end()); } std::u16string NumberToString16(float number) { return ASCIIToUTF16(NumberToString(number)); } +std::u16string NumberToString16(int32_t number) { + return ASCIIToUTF16(NumberToString(number)); +} + +std::u16string NumberToString16(unsigned int number) { + return ASCIIToUTF16(NumberToString(number)); +} + +std::u16string NumberToString16(double number) { + return ASCIIToUTF16(NumberToString(number)); +} + std::string NumberToString(int32_t number) { return std::to_string(number); } @@ -41,6 +73,14 @@ 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); +} + +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); } @@ -56,6 +96,20 @@ std::string JoinString(std::vector tokens, std::string delimiter) { return imploded.str(); } +std::u16string JoinString(std::vector tokens, + std::u16string delimiter) { + std::u16string result; + for (size_t i = 0; i < tokens.size(); i++) { + if (i == tokens.size() - 1) { + result.append(tokens[i]); + } else { + result.append(tokens[i]); + result.append(delimiter); + } + } + return result; +} + void ReplaceChars(std::string in, std::string from, std::string to, @@ -68,6 +122,18 @@ void ReplaceChars(std::string in, *out = in; } +void ReplaceChars(std::u16string in, + std::u16string from, + std::u16string to, + std::u16string* out) { + size_t pos = in.find(from); + while (pos != std::u16string::npos) { + in.replace(pos, from.size(), to); + pos = in.find(from, pos + to.size()); + } + *out = in; +} + const std::string& EmptyString() { static const base::NoDestructor s; return *s; diff --git a/engine/src/flutter/third_party/accessibility/base/string_utils.h b/engine/src/flutter/third_party/accessibility/base/string_utils.h index 227c6518453..0604db96c4d 100644 --- a/engine/src/flutter/third_party/accessibility/base/string_utils.h +++ b/engine/src/flutter/third_party/accessibility/base/string_utils.h @@ -25,21 +25,34 @@ std::string StringPrintf(const std::string& format, Args... args) { std::u16string ASCIIToUTF16(std::string src); std::u16string UTF8ToUTF16(std::string src); 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(double number); + std::string NumberToString(unsigned int number); std::string NumberToString(int32_t number); std::string NumberToString(float number); +std::string NumberToString(double number); std::string ToUpperASCII(std::string str); std::string ToLowerASCII(std::string str); std::string JoinString(std::vector tokens, std::string delimiter); +std::u16string JoinString(std::vector tokens, + std::u16string delimiter); + void ReplaceChars(std::string in, std::string from, std::string to, std::string* out); - +void ReplaceChars(std::u16string in, + std::u16string from, + std::u16string to, + std::u16string* out); bool LowerCaseEqualsASCII(std::string a, std::string b); bool ContainsOnlyChars(std::u16string str, char16_t ch); diff --git a/engine/src/flutter/third_party/accessibility/base/win/string_conversion.cc b/engine/src/flutter/third_party/accessibility/base/win/string_conversion.cc new file mode 100644 index 00000000000..15bff3ce7b1 --- /dev/null +++ b/engine/src/flutter/third_party/accessibility/base/win/string_conversion.cc @@ -0,0 +1,60 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// TODO(gw280): This is copied from shell/platform/win. When +// https://github.com/flutter/flutter/issues/75653 is fixed, we should +// deduplicate these and put them in fml. +#include "string_conversion.h" + +#include + +namespace base { +namespace win { + +std::string Utf8FromUtf16(const std::wstring& utf16_string) { + if (utf16_string.empty()) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string.data(), + static_cast(utf16_string.length()), nullptr, 0, nullptr, nullptr); + if (target_length == 0) { + return std::string(); + } + std::string utf8_string; + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string.data(), + static_cast(utf16_string.length()), utf8_string.data(), + target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} + +std::wstring Utf16FromUtf8(const std::string& utf8_string) { + if (utf8_string.empty()) { + return std::wstring(); + } + int target_length = + ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8_string.data(), + static_cast(utf8_string.length()), nullptr, 0); + if (target_length == 0) { + return std::wstring(); + } + std::wstring utf16_string; + utf16_string.resize(target_length); + int converted_length = + ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8_string.data(), + static_cast(utf8_string.length()), + utf16_string.data(), target_length); + if (converted_length == 0) { + return std::wstring(); + } + return utf16_string; +} + +} // namespace win +} // namespace base diff --git a/engine/src/flutter/third_party/accessibility/base/win/string_conversion.h b/engine/src/flutter/third_party/accessibility/base/win/string_conversion.h new file mode 100644 index 00000000000..471268f4d04 --- /dev/null +++ b/engine/src/flutter/third_party/accessibility/base/win/string_conversion.h @@ -0,0 +1,24 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_STRING_CONVERSION_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_STRING_CONVERSION_H_ + +#include + +namespace base { +namespace win { + +// Converts a string from UTF-16 to UTF-8. Returns an empty string if the +// input is not valid UTF-16. +std::string Utf8FromUtf16(const std::wstring& utf16_string); + +// Converts a string from UTF-8 to UTF-16. Returns an empty string if the +// input is not valid UTF-8. +std::wstring Utf16FromUtf8(const std::string& utf8_string); + +} // namespace win +} // namespace base + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_STRING_CONVERSION_H_