Extract WideToUTF16String/UTF16StringToWide to FML (flutter/engine#39020)

This commit is contained in:
Chris Bracken 2023-01-19 22:55:47 -08:00 committed by GitHub
parent 1193c711f4
commit 1dd1f02bc4
11 changed files with 98 additions and 65 deletions

View File

@ -23,4 +23,16 @@ std::wstring Utf8ToWideString(const std::string_view str) {
return converter.from_bytes(str.data());
}
std::u16string WideStringToUtf16(const std::wstring_view str) {
static_assert(sizeof(std::wstring::value_type) ==
sizeof(std::u16string::value_type));
return {begin(str), end(str)};
}
std::wstring Utf16ToWideString(const std::u16string_view str) {
static_assert(sizeof(std::wstring::value_type) ==
sizeof(std::u16string::value_type));
return {begin(str), end(str)};
}
} // namespace fml

View File

@ -16,6 +16,12 @@ std::string WideStringToUtf8(const std::wstring_view str);
// string.
std::wstring Utf8ToWideString(const std::string_view str);
// Returns a UTF-16 encoded equivalent of a UTF-16 encoded wide string.
std::u16string WideStringToUtf16(const std::wstring_view str);
// Returns a UTF-16 encoded wide string equivalent of a UTF-16 string.
std::wstring Utf16ToWideString(const std::u16string_view str);
} // namespace fml
#endif // FLUTTER_FML_PLATFORM_WIN_WSTRING_CONVERSION_H_

View File

@ -9,7 +9,7 @@
namespace fml {
namespace testing {
TEST(StringConversion, Utf16ToWideStringEmpty) {
TEST(StringConversion, Utf8ToWideStringEmpty) {
EXPECT_EQ(Utf8ToWideString(""), L"");
}
@ -33,5 +33,29 @@ TEST(StringConversion, WideStringToUtf8Unicode) {
EXPECT_EQ(WideStringToUtf8(L"\x2603"), "\xe2\x98\x83");
}
TEST(StringConversion, WideStringToUtf16Empty) {
EXPECT_EQ(WideStringToUtf16(L""), u"");
}
TEST(StringConversion, WideStringToUtf16Ascii) {
EXPECT_EQ(WideStringToUtf16(L"abc123"), u"abc123");
}
TEST(StringConversion, WideStringToUtf16Unicode) {
EXPECT_EQ(WideStringToUtf16(L"\xe2\x98\x83"), u"\xe2\x98\x83");
}
TEST(StringConversion, Utf16ToWideStringEmpty) {
EXPECT_EQ(Utf16ToWideString(u""), L"");
}
TEST(StringConversion, Utf16ToWideStringAscii) {
EXPECT_EQ(Utf16ToWideString(u"abc123"), L"abc123");
}
TEST(StringConversion, Utf16ToWideStringUtf8Unicode) {
EXPECT_EQ(Utf16ToWideString(u"\xe2\x98\x83"), L"\xe2\x98\x83");
}
} // namespace testing
} // namespace fml

View File

@ -6,6 +6,7 @@
#include <chrono>
#include "flutter/fml/platform/win/wstring_conversion.h"
#include "flutter/shell/platform/common/accessibility_bridge.h"
#include "flutter/shell/platform/windows/keyboard_key_channel_handler.h"
#include "flutter/shell/platform/windows/keyboard_key_embedder_handler.h"
@ -666,7 +667,7 @@ void FlutterWindowsView::AnnounceAlert(const std::wstring& text) {
if (!alert_delegate) {
return;
}
alert_delegate->SetText(base::WideToUTF16(text));
alert_delegate->SetText(fml::WideStringToUtf16(text));
ui::AXPlatformNodeWin* alert_node = binding_handler_->GetAlert();
NotifyWinEventWrapper(alert_node, ax::mojom::Event::kAlert);
}

View File

@ -106,6 +106,7 @@ source_set("ax") {
"oleacc.lib",
"uiautomationcore.lib",
]
deps = [ "//flutter/fml:string_conversion" ]
}
public_deps = [

View File

@ -19,6 +19,7 @@
#include "ax/ax_tree_id.h"
#include "ax/ax_tree_update.h"
#include "ax/test_ax_tree_manager.h"
#include "flutter/fml/platform/win/wstring_conversion.h"
#include "gtest/gtest.h"
namespace ui {
@ -28,10 +29,6 @@ using TestPositionRange = AXRange<AXPosition<AXNodePosition, AXNode>>;
namespace {
std::u16string WideToUTF16(const std::wstring wide) {
return std::u16string(wide.begin(), wide.end());
}
constexpr AXNode::AXID ROOT_ID = 1;
constexpr AXNode::AXID BUTTON_ID = 2;
constexpr AXNode::AXID CHECK_BOX_ID = 3;
@ -43,20 +40,20 @@ constexpr AXNode::AXID STATIC_TEXT2_ID = 8;
constexpr AXNode::AXID INLINE_BOX2_ID = 9;
// A group of basic and extended characters.
constexpr const wchar_t* kGraphemeClusters[] = {
constexpr const char16_t* kGraphemeClusters[] = {
// The English word "hey" consisting of four ASCII characters.
L"h",
L"e",
L"y",
u"h",
u"e",
u"y",
// A Hindi word (which means "Hindi") consisting of two Devanagari
// grapheme clusters.
L"\x0939\x093F",
L"\x0928\x094D\x0926\x0940",
u"\x0939\x093F",
u"\x0928\x094D\x0926\x0940",
// A Thai word (which means "feel") consisting of three Thai grapheme
// clusters.
L"\x0E23\x0E39\x0E49",
L"\x0E2A\x0E36",
L"\x0E01",
u"\x0E23\x0E39\x0E49",
u"\x0E2A\x0E36",
u"\x0E01",
};
class AXPositionTest : public testing::Test, public TestAXTreeManager {
@ -419,7 +416,7 @@ std::unique_ptr<AXTree> AXPositionTest::CreateMultilingualDocument(
std::u16string english_text;
for (int i = 0; i < 3; ++i) {
std::u16string grapheme = WideToUTF16(kGraphemeClusters[i]);
std::u16string grapheme = kGraphemeClusters[i];
EXPECT_EQ(1u, grapheme.length())
<< "All English characters should be one UTF16 code unit in length.";
text_offsets->push_back(text_offsets->back() +
@ -429,7 +426,7 @@ std::unique_ptr<AXTree> AXPositionTest::CreateMultilingualDocument(
std::u16string hindi_text;
for (int i = 3; i < 5; ++i) {
std::u16string grapheme = WideToUTF16(kGraphemeClusters[i]);
std::u16string grapheme = kGraphemeClusters[i];
EXPECT_LE(2u, grapheme.length()) << "All Hindi characters should be two "
"or more UTF16 code units in length.";
text_offsets->push_back(text_offsets->back() +
@ -439,7 +436,7 @@ std::unique_ptr<AXTree> AXPositionTest::CreateMultilingualDocument(
std::u16string thai_text;
for (int i = 5; i < 8; ++i) {
std::u16string grapheme = WideToUTF16(kGraphemeClusters[i]);
std::u16string grapheme = kGraphemeClusters[i];
EXPECT_LT(0u, grapheme.length())
<< "One of the Thai characters should be one UTF16 code unit, "
"whilst others should be two or more.";
@ -618,7 +615,7 @@ TEST_F(AXPositionTest, ToString) {
AXNodeData static_text_data_2;
static_text_data_2.id = 3;
static_text_data_2.role = ax::mojom::Role::kStaticText;
static_text_data_2.SetName(WideToUTF16(L"\xfffc"));
static_text_data_2.SetName(u"\xfffc");
AXNodeData static_text_data_3;
static_text_data_3.id = 4;
@ -876,7 +873,7 @@ TEST_F(AXPositionTest, GetTextFromNullPosition) {
TestPositionType text_position = AXNodePosition::CreateNullPosition();
ASSERT_NE(nullptr, text_position);
ASSERT_TRUE(text_position->IsNullPosition());
ASSERT_EQ(WideToUTF16(L""), text_position->GetText());
ASSERT_EQ(u"", text_position->GetText());
}
TEST_F(AXPositionTest, GetTextFromRoot) {
@ -885,7 +882,7 @@ TEST_F(AXPositionTest, GetTextFromRoot) {
ax::mojom::TextAffinity::kUpstream);
ASSERT_NE(nullptr, text_position);
ASSERT_TRUE(text_position->IsTextPosition());
ASSERT_EQ(WideToUTF16(L"Line 1\nLine 2"), text_position->GetText());
ASSERT_EQ(u"Line 1\nLine 2", text_position->GetText());
}
TEST_F(AXPositionTest, GetTextFromButton) {
@ -894,7 +891,7 @@ TEST_F(AXPositionTest, GetTextFromButton) {
ax::mojom::TextAffinity::kUpstream);
ASSERT_NE(nullptr, text_position);
ASSERT_TRUE(text_position->IsTextPosition());
ASSERT_EQ(WideToUTF16(L""), text_position->GetText());
ASSERT_EQ(u"", text_position->GetText());
}
TEST_F(AXPositionTest, GetTextFromCheckbox) {
@ -903,7 +900,7 @@ TEST_F(AXPositionTest, GetTextFromCheckbox) {
ax::mojom::TextAffinity::kUpstream);
ASSERT_NE(nullptr, text_position);
ASSERT_TRUE(text_position->IsTextPosition());
ASSERT_EQ(WideToUTF16(L""), text_position->GetText());
ASSERT_EQ(u"", text_position->GetText());
}
TEST_F(AXPositionTest, GetTextFromTextField) {
@ -912,7 +909,7 @@ TEST_F(AXPositionTest, GetTextFromTextField) {
ax::mojom::TextAffinity::kUpstream);
ASSERT_NE(nullptr, text_position);
ASSERT_TRUE(text_position->IsTextPosition());
ASSERT_EQ(WideToUTF16(L"Line 1\nLine 2"), text_position->GetText());
ASSERT_EQ(u"Line 1\nLine 2", text_position->GetText());
}
TEST_F(AXPositionTest, GetTextFromStaticText) {
@ -921,7 +918,7 @@ TEST_F(AXPositionTest, GetTextFromStaticText) {
ax::mojom::TextAffinity::kUpstream);
ASSERT_NE(nullptr, text_position);
ASSERT_TRUE(text_position->IsTextPosition());
ASSERT_EQ(WideToUTF16(L"Line 1"), text_position->GetText());
ASSERT_EQ(u"Line 1", text_position->GetText());
}
TEST_F(AXPositionTest, GetTextFromInlineTextBox) {
@ -930,7 +927,7 @@ TEST_F(AXPositionTest, GetTextFromInlineTextBox) {
ax::mojom::TextAffinity::kUpstream);
ASSERT_NE(nullptr, text_position);
ASSERT_TRUE(text_position->IsTextPosition());
ASSERT_EQ(WideToUTF16(L"Line 1"), text_position->GetText());
ASSERT_EQ(u"Line 1", text_position->GetText());
}
TEST_F(AXPositionTest, GetTextFromLineBreak) {
@ -939,7 +936,7 @@ TEST_F(AXPositionTest, GetTextFromLineBreak) {
ax::mojom::TextAffinity::kUpstream);
ASSERT_NE(nullptr, text_position);
ASSERT_TRUE(text_position->IsTextPosition());
ASSERT_EQ(WideToUTF16(L"\n"), text_position->GetText());
ASSERT_EQ(u"\n", text_position->GetText());
}
TEST_F(AXPositionTest, GetMaxTextOffsetFromNullPosition) {
@ -1106,7 +1103,7 @@ TEST_F(AXPositionTest, GetMaxTextOffsetAndGetTextWithGeneratedContent) {
ASSERT_NE(nullptr, text_position);
EXPECT_TRUE(text_position->IsTextPosition());
EXPECT_EQ(38, text_position->MaxTextOffset());
EXPECT_EQ(WideToUTF16(L"Placeholder from generated content3.14"),
EXPECT_EQ(u"Placeholder from generated content3.14",
text_position->GetText());
}
@ -7712,10 +7709,10 @@ TEST_F(AXPositionTest, EmptyObjectReplacedByCharacterTextNavigation) {
GetTreeID(), root_1.id, 0 /* text_offset */,
ax::mojom::TextAffinity::kDownstream);
expected_text = WideToUTF16(L"Hello ") + AXNodePosition::kEmbeddedCharacter +
WideToUTF16(L" world3.14") +
AXNodePosition::kEmbeddedCharacter + WideToUTF16(L"hey") +
AXNodePosition::kEmbeddedCharacter;
expected_text =
std::u16string(u"Hello ") + AXNodePosition::kEmbeddedCharacter +
std::u16string(u" world3.14") + AXNodePosition::kEmbeddedCharacter +
std::u16string(u"hey") + AXNodePosition::kEmbeddedCharacter;
ASSERT_EQ(expected_text, position->GetText());
// MaxTextOffset() with an embedded object replacement character.

View File

@ -349,7 +349,7 @@ TEST_F(AXPlatformNodeTextProviderTest,
base::win::ScopedBstr text_content;
EXPECT_HRESULT_SUCCEEDED(
text_range_provider->GetText(-1, text_content.Receive()));
EXPECT_EQ(base::WideToUTF16(text_content.Get()),
EXPECT_EQ(fml::WideStringToUtf16(text_content.Get()),
u"Dialog label.Dialog description." + kEmbeddedCharacterAsString +
u"ok.Some more detail " + u"about dialog.");

View File

@ -13,6 +13,7 @@
#include "ax/platform/ax_platform_node_win.h"
#include "ax/platform/ax_platform_tree_manager.h"
#include "base/win/variant_vector.h"
#include "flutter/fml/platform/win/wstring_conversion.h"
#define UIA_VALIDATE_TEXTRANGEPROVIDER_CALL() \
if (!GetOwner() || !GetOwner()->GetDelegate() || !start() || \
@ -483,7 +484,7 @@ HRESULT AXPlatformNodeTextRangeProviderWin::FindText(
ScopedAXEmbeddedObjectBehaviorSetter ax_embedded_object_behavior(
AXEmbeddedObjectBehavior::kSuppressCharacter);
std::u16string search_string = base::WideToUTF16(string);
std::u16string search_string = fml::WideStringToUtf16(string);
if (search_string.length() <= 0)
return E_INVALIDARG;
@ -703,7 +704,7 @@ HRESULT AXPlatformNodeTextRangeProviderWin::GetText(int max_count, BSTR* text) {
if (max_count < -1)
return E_INVALIDARG;
std::wstring full_text = base::UTF16ToWide(GetString(max_count));
std::wstring full_text = fml::Utf16ToWideString(GetString(max_count));
if (!full_text.empty()) {
size_t length = full_text.length();

View File

@ -38,6 +38,7 @@
#include "base/logging.h"
#include "base/win/atl_module.h"
#include "base/win/display.h"
#include "flutter/fml/platform/win/wstring_conversion.h"
#include "gfx/geometry/rect_conversions.h"
// From ax.constants.mojom
@ -963,7 +964,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_accDefaultAction(VARIANT var_id,
return S_FALSE;
}
*def_action = ::SysAllocString(base::UTF16ToWide(action_verb).c_str());
*def_action = ::SysAllocString(fml::Utf16ToWideString(action_verb).c_str());
BASE_DCHECK(def_action);
return S_OK;
}
@ -1054,7 +1055,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_accName(VARIANT var_id, BSTR* name_bstr) {
if (name.empty() && !has_name)
return S_FALSE;
*name_bstr = ::SysAllocString(base::UTF16ToWide(name).c_str());
*name_bstr = ::SysAllocString(fml::Utf16ToWideString(name).c_str());
return S_OK;
}
@ -1749,7 +1750,7 @@ IFACEMETHODIMP AXPlatformNodeWin::SetValue(LPCWSTR value) {
AXActionData data;
data.action = ax::mojom::Action::kSetValue;
data.value = base::UTF16ToUTF8(base::WideToUTF16(value));
data.value = base::UTF16ToUTF8(fml::WideStringToUtf16(value));
if (GetDelegate()->AccessibilityPerformAction(data))
return S_OK;
return E_FAIL;
@ -2132,20 +2133,20 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id,
switch (property_id) {
case UIA_AriaPropertiesPropertyId:
result->vt = VT_BSTR;
result->bstrVal =
::SysAllocString(base::UTF16ToWide(ComputeUIAProperties()).c_str());
result->bstrVal = ::SysAllocString(
fml::Utf16ToWideString(ComputeUIAProperties()).c_str());
break;
case UIA_AriaRolePropertyId:
result->vt = VT_BSTR;
result->bstrVal =
::SysAllocString(base::UTF16ToWide(UIAAriaRole()).c_str());
::SysAllocString(fml::Utf16ToWideString(UIAAriaRole()).c_str());
break;
case UIA_AutomationIdPropertyId:
V_VT(result) = VT_BSTR;
V_BSTR(result) = ::SysAllocString(
base::UTF16ToWide(GetDelegate()->GetAuthorUniqueId()).c_str());
fml::Utf16ToWideString(GetDelegate()->GetAuthorUniqueId()).c_str());
break;
case UIA_ClassNamePropertyId:
@ -2314,8 +2315,8 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id,
std::u16string localized_control_type = GetRoleDescription();
if (!localized_control_type.empty()) {
result->vt = VT_BSTR;
result->bstrVal =
::SysAllocString(base::UTF16ToWide(localized_control_type).c_str());
result->bstrVal = ::SysAllocString(
fml::Utf16ToWideString(localized_control_type).c_str());
}
// If a role description has not been provided, leave as VT_EMPTY.
// UIA core handles Localized Control type for some built-in types and
@ -2466,7 +2467,7 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id,
if (!localized_landmark_type.empty()) {
result->vt = VT_BSTR;
result->bstrVal = ::SysAllocString(
base::UTF16ToWide(localized_landmark_type).c_str());
fml::Utf16ToWideString(localized_landmark_type).c_str());
}
break;
}
@ -2525,7 +2526,7 @@ HRESULT AXPlatformNodeWin::GetPropertyValueImpl(PROPERTYID property_id,
// convention here and when we fire events via ::NotifyWinEvent().
result->vt = VT_BSTR;
result->bstrVal = ::SysAllocString(
base::UTF16ToWide(base::NumberToString16(-GetUniqueId())).c_str());
fml::Utf16ToWideString(base::NumberToString16(-GetUniqueId())).c_str());
}
return S_OK;
@ -5314,7 +5315,7 @@ BSTR AXPlatformNodeWin::GetValueAttributeAsBstr(AXPlatformNodeWin* target) {
value_text = base::NumberToString16(red * 100 / 255) + u"% red " +
base::NumberToString16(green * 100 / 255) + u"% green " +
base::NumberToString16(blue * 100 / 255) + u"% blue";
BSTR value = ::SysAllocString(base::UTF16ToWide(value_text).c_str());
BSTR value = ::SysAllocString(fml::Utf16ToWideString(value_text).c_str());
BASE_DCHECK(value);
return value;
}
@ -5325,7 +5326,7 @@ BSTR AXPlatformNodeWin::GetValueAttributeAsBstr(AXPlatformNodeWin* target) {
if (target->GetData().role == ax::mojom::Role::kRootWebArea ||
target->GetData().role == ax::mojom::Role::kWebArea) {
result = base::UTF8ToUTF16(target->GetDelegate()->GetTreeData().url);
BSTR value = ::SysAllocString(base::UTF16ToWide(result).c_str());
BSTR value = ::SysAllocString(fml::Utf16ToWideString(result).c_str());
BASE_DCHECK(value);
return value;
}
@ -5335,7 +5336,7 @@ BSTR AXPlatformNodeWin::GetValueAttributeAsBstr(AXPlatformNodeWin* target) {
//
if (target->GetData().role == ax::mojom::Role::kLink) {
result = target->GetString16Attribute(ax::mojom::StringAttribute::kUrl);
BSTR value = ::SysAllocString(base::UTF16ToWide(result).c_str());
BSTR value = ::SysAllocString(fml::Utf16ToWideString(result).c_str());
BASE_DCHECK(value);
return value;
}
@ -5350,7 +5351,7 @@ BSTR AXPlatformNodeWin::GetValueAttributeAsBstr(AXPlatformNodeWin* target) {
if (target->GetFloatAttribute(ax::mojom::FloatAttribute::kValueForRange,
&fval)) {
result = base::NumberToString16(fval);
BSTR value = ::SysAllocString(base::UTF16ToWide(result).c_str());
BSTR value = ::SysAllocString(fml::Utf16ToWideString(result).c_str());
BASE_DCHECK(value);
return value;
}
@ -5359,7 +5360,7 @@ BSTR AXPlatformNodeWin::GetValueAttributeAsBstr(AXPlatformNodeWin* target) {
if (result.empty() && target->IsRichTextField())
result = target->GetInnerText();
BSTR value = ::SysAllocString(base::UTF16ToWide(result).c_str());
BSTR value = ::SysAllocString(fml::Utf16ToWideString(result).c_str());
BASE_DCHECK(value);
return value;
}
@ -5372,7 +5373,7 @@ HRESULT AXPlatformNodeWin::GetStringAttributeAsBstr(
if (!GetString16Attribute(attribute, &str))
return S_FALSE;
*value_bstr = ::SysAllocString(base::UTF16ToWide(str).c_str());
*value_bstr = ::SysAllocString(fml::Utf16ToWideString(str).c_str());
BASE_DCHECK(*value_bstr);
return S_OK;
@ -5380,7 +5381,7 @@ HRESULT AXPlatformNodeWin::GetStringAttributeAsBstr(
HRESULT AXPlatformNodeWin::GetNameAsBstr(BSTR* value_bstr) const {
std::u16string str = GetNameAsString16();
*value_bstr = ::SysAllocString(base::UTF16ToWide(str).c_str());
*value_bstr = ::SysAllocString(fml::Utf16ToWideString(str).c_str());
BASE_DCHECK(*value_bstr);
return S_OK;
}
@ -5490,14 +5491,14 @@ BSTR AXPlatformNodeWin::GetFontNameAttributeAsBSTR() const {
const std::u16string string =
GetInheritedString16Attribute(ax::mojom::StringAttribute::kFontFamily);
return ::SysAllocString(base::UTF16ToWide(string).c_str());
return ::SysAllocString(fml::Utf16ToWideString(string).c_str());
}
BSTR AXPlatformNodeWin::GetStyleNameAttributeAsBSTR() const {
std::u16string style_name =
GetDelegate()->GetStyleNameAttributeAsLocalizedString();
return ::SysAllocString(base::UTF16ToWide(style_name).c_str());
return ::SysAllocString(fml::Utf16ToWideString(style_name).c_str());
}
TextDecorationLineStyle AXPlatformNodeWin::GetUIATextDecorationStyle(

View File

@ -72,14 +72,6 @@ std::string UTF16ToUTF8(std::u16string src) {
return fml::Utf16ToUtf8(src);
}
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));
}

View File

@ -26,8 +26,6 @@ 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(unsigned int number);
std::u16string NumberToString16(int32_t number);