Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit baa16c8

Browse files
committed
Extract WideToUTF16String/UTF16StringToWide to FML
In third_party/accessibility, for string conversion, we use a mix of: * FML * third_party/accessibility base string utility functions * static functions local to the translation unit itself This moves all conversions between UTF16 and wide strings to FML. Note that this implementation is only safe on platforms where: * the size of wchar_t and char16_t are the same * the encoding of wchar_t and char16_t are both UTF-16 which is the case for Windows, hence why these functions are implemented in a Windows-specific translation unit (wstring_conversion). Issue: flutter/flutter#118811
1 parent 8ed6790 commit baa16c8

8 files changed

+75
-33
lines changed

fml/platform/win/wstring_conversion.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,16 @@ std::wstring Utf8ToWideString(const std::string_view str) {
2323
return converter.from_bytes(str.data());
2424
}
2525

26+
std::u16string WideStringToUtf16(const std::wstring_view str) {
27+
static_assert(sizeof(std::wstring::value_type) ==
28+
sizeof(std::u16string::value_type));
29+
return {begin(str), end(str)};
30+
}
31+
32+
std::wstring Utf16ToWideString(const std::u16string_view str) {
33+
static_assert(sizeof(std::wstring::value_type) ==
34+
sizeof(std::u16string::value_type));
35+
return {begin(str), end(str)};
36+
}
37+
2638
} // namespace fml

fml/platform/win/wstring_conversion.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ std::string WideStringToUtf8(const std::wstring_view str);
1616
// string.
1717
std::wstring Utf8ToWideString(const std::string_view str);
1818

19+
// Returns a UTF-16 encoded equivalent of a UTF-16 encoded wide string.
20+
std::u16string WideStringToUtf16(const std::wstring_view str);
21+
22+
// Returns a UTF-16 encoded wide string equivalent of a UTF-16 string.
23+
std::wstring Utf16ToWideString(const std::u16string_view str);
24+
1925
} // namespace fml
2026

2127
#endif // FLUTTER_FML_PLATFORM_WIN_WSTRING_CONVERSION_H_

fml/platform/win/wstring_conversion_unittests.cc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,29 @@ TEST(StringConversion, WideStringToUtf8Unicode) {
3333
EXPECT_EQ(WideStringToUtf8(L"\x2603"), "\xe2\x98\x83");
3434
}
3535

36+
TEST(StringConversion, WideStringToUtf16Empty) {
37+
EXPECT_EQ(WideStringToUtf16(L""), u"");
38+
}
39+
40+
TEST(StringConversion, WideStringToUtf16Ascii) {
41+
EXPECT_EQ(WideStringToUtf16(L"abc123"), u"abc123");
42+
}
43+
44+
TEST(StringConversion, WideStringToUtf16Unicode) {
45+
EXPECT_EQ(WideStringToUtf16(L"\xe2\x98\x83"), u"\x2603");
46+
}
47+
48+
TEST(StringConversion, Utf16ToWideStringEmpty) {
49+
EXPECT_EQ(Utf16ToWideString(u""), L"");
50+
}
51+
52+
TEST(StringConversion, Utf16ToWideStringAscii) {
53+
EXPECT_EQ(Utf16ToWideString(u"abc123"), L"abc123");
54+
}
55+
56+
TEST(StringConversion, Utf16ToWideStringUtf8Unicode) {
57+
EXPECT_EQ(Utf16ToWideString(u"\x2603"), L"\xe2\x98\x83");
58+
}
59+
3660
} // namespace testing
3761
} // namespace fml

third_party/accessibility/ax/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ source_set("ax") {
106106
"oleacc.lib",
107107
"uiautomationcore.lib",
108108
]
109+
deps = [ "//flutter/fml:string_conversion" ]
109110
}
110111

111112
public_deps = [

third_party/accessibility/ax/ax_node_position_unittest.cc

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "ax/ax_tree_id.h"
2020
#include "ax/ax_tree_update.h"
2121
#include "ax/test_ax_tree_manager.h"
22+
#include "flutter/fml/platform/win/wstring_conversion.h"
2223
#include "gtest/gtest.h"
2324

2425
namespace ui {
@@ -28,10 +29,6 @@ using TestPositionRange = AXRange<AXPosition<AXNodePosition, AXNode>>;
2829

2930
namespace {
3031

31-
std::u16string WideToUTF16(const std::wstring wide) {
32-
return std::u16string(wide.begin(), wide.end());
33-
}
34-
3532
constexpr AXNode::AXID ROOT_ID = 1;
3633
constexpr AXNode::AXID BUTTON_ID = 2;
3734
constexpr AXNode::AXID CHECK_BOX_ID = 3;
@@ -43,20 +40,20 @@ constexpr AXNode::AXID STATIC_TEXT2_ID = 8;
4340
constexpr AXNode::AXID INLINE_BOX2_ID = 9;
4441

4542
// A group of basic and extended characters.
46-
constexpr const wchar_t* kGraphemeClusters[] = {
43+
constexpr const char16_t* kGraphemeClusters[] = {
4744
// The English word "hey" consisting of four ASCII characters.
48-
L"h",
49-
L"e",
50-
L"y",
45+
u"h",
46+
u"e",
47+
u"y",
5148
// A Hindi word (which means "Hindi") consisting of two Devanagari
5249
// grapheme clusters.
53-
L"\x0939\x093F",
54-
L"\x0928\x094D\x0926\x0940",
50+
u"\x0939\x093F",
51+
u"\x0928\x094D\x0926\x0940",
5552
// A Thai word (which means "feel") consisting of three Thai grapheme
5653
// clusters.
57-
L"\x0E23\x0E39\x0E49",
58-
L"\x0E2A\x0E36",
59-
L"\x0E01",
54+
u"\x0E23\x0E39\x0E49",
55+
u"\x0E2A\x0E36",
56+
u"\x0E01",
6057
};
6158

6259
class AXPositionTest : public testing::Test, public TestAXTreeManager {
@@ -419,7 +416,7 @@ std::unique_ptr<AXTree> AXPositionTest::CreateMultilingualDocument(
419416

420417
std::u16string english_text;
421418
for (int i = 0; i < 3; ++i) {
422-
std::u16string grapheme = WideToUTF16(kGraphemeClusters[i]);
419+
std::u16string grapheme = kGraphemeClusters[i];
423420
EXPECT_EQ(1u, grapheme.length())
424421
<< "All English characters should be one UTF16 code unit in length.";
425422
text_offsets->push_back(text_offsets->back() +
@@ -429,7 +426,7 @@ std::unique_ptr<AXTree> AXPositionTest::CreateMultilingualDocument(
429426

430427
std::u16string hindi_text;
431428
for (int i = 3; i < 5; ++i) {
432-
std::u16string grapheme = WideToUTF16(kGraphemeClusters[i]);
429+
std::u16string grapheme = kGraphemeClusters[i];
433430
EXPECT_LE(2u, grapheme.length()) << "All Hindi characters should be two "
434431
"or more UTF16 code units in length.";
435432
text_offsets->push_back(text_offsets->back() +
@@ -439,7 +436,7 @@ std::unique_ptr<AXTree> AXPositionTest::CreateMultilingualDocument(
439436

440437
std::u16string thai_text;
441438
for (int i = 5; i < 8; ++i) {
442-
std::u16string grapheme = WideToUTF16(kGraphemeClusters[i]);
439+
std::u16string grapheme = kGraphemeClusters[i];
443440
EXPECT_LT(0u, grapheme.length())
444441
<< "One of the Thai characters should be one UTF16 code unit, "
445442
"whilst others should be two or more.";
@@ -618,7 +615,7 @@ TEST_F(AXPositionTest, ToString) {
618615
AXNodeData static_text_data_2;
619616
static_text_data_2.id = 3;
620617
static_text_data_2.role = ax::mojom::Role::kStaticText;
621-
static_text_data_2.SetName(WideToUTF16(L"\xfffc"));
618+
static_text_data_2.SetName(u"\xfffc");
622619

623620
AXNodeData static_text_data_3;
624621
static_text_data_3.id = 4;
@@ -876,7 +873,7 @@ TEST_F(AXPositionTest, GetTextFromNullPosition) {
876873
TestPositionType text_position = AXNodePosition::CreateNullPosition();
877874
ASSERT_NE(nullptr, text_position);
878875
ASSERT_TRUE(text_position->IsNullPosition());
879-
ASSERT_EQ(WideToUTF16(L""), text_position->GetText());
876+
ASSERT_EQ(u"", text_position->GetText());
880877
}
881878

882879
TEST_F(AXPositionTest, GetTextFromRoot) {
@@ -885,7 +882,7 @@ TEST_F(AXPositionTest, GetTextFromRoot) {
885882
ax::mojom::TextAffinity::kUpstream);
886883
ASSERT_NE(nullptr, text_position);
887884
ASSERT_TRUE(text_position->IsTextPosition());
888-
ASSERT_EQ(WideToUTF16(L"Line 1\nLine 2"), text_position->GetText());
885+
ASSERT_EQ(u"Line 1\nLine 2", text_position->GetText());
889886
}
890887

891888
TEST_F(AXPositionTest, GetTextFromButton) {
@@ -894,7 +891,7 @@ TEST_F(AXPositionTest, GetTextFromButton) {
894891
ax::mojom::TextAffinity::kUpstream);
895892
ASSERT_NE(nullptr, text_position);
896893
ASSERT_TRUE(text_position->IsTextPosition());
897-
ASSERT_EQ(WideToUTF16(L""), text_position->GetText());
894+
ASSERT_EQ(u"", text_position->GetText());
898895
}
899896

900897
TEST_F(AXPositionTest, GetTextFromCheckbox) {
@@ -903,7 +900,7 @@ TEST_F(AXPositionTest, GetTextFromCheckbox) {
903900
ax::mojom::TextAffinity::kUpstream);
904901
ASSERT_NE(nullptr, text_position);
905902
ASSERT_TRUE(text_position->IsTextPosition());
906-
ASSERT_EQ(WideToUTF16(L""), text_position->GetText());
903+
ASSERT_EQ(u"", text_position->GetText());
907904
}
908905

909906
TEST_F(AXPositionTest, GetTextFromTextField) {
@@ -912,7 +909,7 @@ TEST_F(AXPositionTest, GetTextFromTextField) {
912909
ax::mojom::TextAffinity::kUpstream);
913910
ASSERT_NE(nullptr, text_position);
914911
ASSERT_TRUE(text_position->IsTextPosition());
915-
ASSERT_EQ(WideToUTF16(L"Line 1\nLine 2"), text_position->GetText());
912+
ASSERT_EQ(u"Line 1\nLine 2", text_position->GetText());
916913
}
917914

918915
TEST_F(AXPositionTest, GetTextFromStaticText) {
@@ -921,7 +918,7 @@ TEST_F(AXPositionTest, GetTextFromStaticText) {
921918
ax::mojom::TextAffinity::kUpstream);
922919
ASSERT_NE(nullptr, text_position);
923920
ASSERT_TRUE(text_position->IsTextPosition());
924-
ASSERT_EQ(WideToUTF16(L"Line 1"), text_position->GetText());
921+
ASSERT_EQ(u"Line 1", text_position->GetText());
925922
}
926923

927924
TEST_F(AXPositionTest, GetTextFromInlineTextBox) {
@@ -930,7 +927,7 @@ TEST_F(AXPositionTest, GetTextFromInlineTextBox) {
930927
ax::mojom::TextAffinity::kUpstream);
931928
ASSERT_NE(nullptr, text_position);
932929
ASSERT_TRUE(text_position->IsTextPosition());
933-
ASSERT_EQ(WideToUTF16(L"Line 1"), text_position->GetText());
930+
ASSERT_EQ(u"Line 1", text_position->GetText());
934931
}
935932

936933
TEST_F(AXPositionTest, GetTextFromLineBreak) {
@@ -939,7 +936,7 @@ TEST_F(AXPositionTest, GetTextFromLineBreak) {
939936
ax::mojom::TextAffinity::kUpstream);
940937
ASSERT_NE(nullptr, text_position);
941938
ASSERT_TRUE(text_position->IsTextPosition());
942-
ASSERT_EQ(WideToUTF16(L"\n"), text_position->GetText());
939+
ASSERT_EQ(u"\n", text_position->GetText());
943940
}
944941

945942
TEST_F(AXPositionTest, GetMaxTextOffsetFromNullPosition) {
@@ -1106,7 +1103,7 @@ TEST_F(AXPositionTest, GetMaxTextOffsetAndGetTextWithGeneratedContent) {
11061103
ASSERT_NE(nullptr, text_position);
11071104
EXPECT_TRUE(text_position->IsTextPosition());
11081105
EXPECT_EQ(38, text_position->MaxTextOffset());
1109-
EXPECT_EQ(WideToUTF16(L"Placeholder from generated content3.14"),
1106+
EXPECT_EQ(u"Placeholder from generated content3.14",
11101107
text_position->GetText());
11111108
}
11121109

@@ -7712,10 +7709,10 @@ TEST_F(AXPositionTest, EmptyObjectReplacedByCharacterTextNavigation) {
77127709
GetTreeID(), root_1.id, 0 /* text_offset */,
77137710
ax::mojom::TextAffinity::kDownstream);
77147711

7715-
expected_text = WideToUTF16(L"Hello ") + AXNodePosition::kEmbeddedCharacter +
7716-
WideToUTF16(L" world3.14") +
7717-
AXNodePosition::kEmbeddedCharacter + WideToUTF16(L"hey") +
7718-
AXNodePosition::kEmbeddedCharacter;
7712+
expected_text =
7713+
std::u16string(u"Hello ") + AXNodePosition::kEmbeddedCharacter +
7714+
std::u16string(u" world3.14") + AXNodePosition::kEmbeddedCharacter +
7715+
std::u16string(u"hey") + AXNodePosition::kEmbeddedCharacter;
77197716
ASSERT_EQ(expected_text, position->GetText());
77207717

77217718
// MaxTextOffset() with an embedded object replacement character.

third_party/accessibility/ax/platform/ax_platform_node_textprovider_win_unittest.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ TEST_F(AXPlatformNodeTextProviderTest,
349349
base::win::ScopedBstr text_content;
350350
EXPECT_HRESULT_SUCCEEDED(
351351
text_range_provider->GetText(-1, text_content.Receive()));
352-
EXPECT_EQ(base::WideToUTF16(text_content.Get()),
352+
EXPECT_EQ(fml::WideStringToUtf16(text_content.Get()),
353353
u"Dialog label.Dialog description." + kEmbeddedCharacterAsString +
354354
u"ok.Some more detail " + u"about dialog.");
355355

third_party/accessibility/ax/platform/ax_platform_node_textrangeprovider_win.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "ax/platform/ax_platform_node_win.h"
1414
#include "ax/platform/ax_platform_tree_manager.h"
1515
#include "base/win/variant_vector.h"
16+
#include "flutter/fml/platform/win/wstring_conversion.h"
1617

1718
#define UIA_VALIDATE_TEXTRANGEPROVIDER_CALL() \
1819
if (!GetOwner() || !GetOwner()->GetDelegate() || !start() || \
@@ -483,7 +484,7 @@ HRESULT AXPlatformNodeTextRangeProviderWin::FindText(
483484
ScopedAXEmbeddedObjectBehaviorSetter ax_embedded_object_behavior(
484485
AXEmbeddedObjectBehavior::kSuppressCharacter);
485486

486-
std::u16string search_string = base::WideToUTF16(string);
487+
std::u16string search_string = fml::WideStringToUtf16(string);
487488
if (search_string.length() <= 0)
488489
return E_INVALIDARG;
489490

third_party/accessibility/ax/platform/ax_platform_node_win.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "base/logging.h"
3939
#include "base/win/atl_module.h"
4040
#include "base/win/display.h"
41+
#include "flutter/fml/platform/win/wstring_conversion.h"
4142
#include "gfx/geometry/rect_conversions.h"
4243

4344
// From ax.constants.mojom
@@ -1739,7 +1740,7 @@ IFACEMETHODIMP AXPlatformNodeWin::SetValue(LPCWSTR value) {
17391740

17401741
AXActionData data;
17411742
data.action = ax::mojom::Action::kSetValue;
1742-
data.value = base::UTF16ToUTF8(base::WideToUTF16(value));
1743+
data.value = base::UTF16ToUTF8(fml::WideStringToUtf16(value));
17431744
if (GetDelegate()->AccessibilityPerformAction(data))
17441745
return S_OK;
17451746
return E_FAIL;

0 commit comments

Comments
 (0)