OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/views/controls/label.h" | 5 #include "ui/views/controls/label.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/i18n/rtl.h" | 10 #include "base/i18n/rtl.h" |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 return clipboard_text; | 92 return clipboard_text; |
93 } | 93 } |
94 | 94 |
95 enum class SecondaryUiMode { NON_MD, MD }; | 95 enum class SecondaryUiMode { NON_MD, MD }; |
96 | 96 |
97 std::string SecondaryUiModeToString( | 97 std::string SecondaryUiModeToString( |
98 const ::testing::TestParamInfo<SecondaryUiMode>& info) { | 98 const ::testing::TestParamInfo<SecondaryUiMode>& info) { |
99 return info.param == SecondaryUiMode::MD ? "MD" : "NonMD"; | 99 return info.param == SecondaryUiMode::MD ? "MD" : "NonMD"; |
100 } | 100 } |
101 | 101 |
| 102 // Makes an RTL string by mapping 0..6 to [א,ב,ג,ד,ה,ו,ז]. |
| 103 base::string16 ToRTL(const char* ascii) { |
| 104 base::string16 rtl; |
| 105 for (const char* c = ascii; *c; ++c) { |
| 106 if (*c >= '0' && *c <= '6') |
| 107 rtl += L'\x5d0' + (*c - '0'); |
| 108 else |
| 109 rtl += static_cast<base::string16::value_type>(*c); |
| 110 } |
| 111 return rtl; |
| 112 } |
| 113 |
102 } // namespace | 114 } // namespace |
103 | 115 |
104 class LabelTest : public ViewsTestBase { | 116 class LabelTest : public ViewsTestBase { |
105 public: | 117 public: |
106 LabelTest() {} | 118 LabelTest() {} |
107 | 119 |
108 // Called after ViewsTestBase is set up. ViewsTestBase initializes the | 120 // Called after ViewsTestBase is set up. ViewsTestBase initializes the |
109 // MaterialDesignController, so this allows a subclass to influence settings | 121 // MaterialDesignController, so this allows a subclass to influence settings |
110 // used for the remainder of SetUp(). | 122 // used for the remainder of SetUp(). |
111 virtual void OnBaseSetUp() {} | 123 virtual void OnBaseSetUp() {} |
(...skipping 30 matching lines...) Expand all Loading... |
142 private: | 154 private: |
143 Label* label_ = nullptr; | 155 Label* label_ = nullptr; |
144 Widget widget_; | 156 Widget widget_; |
145 | 157 |
146 DISALLOW_COPY_AND_ASSIGN(LabelTest); | 158 DISALLOW_COPY_AND_ASSIGN(LabelTest); |
147 }; | 159 }; |
148 | 160 |
149 // Test fixture for text selection related tests. | 161 // Test fixture for text selection related tests. |
150 class LabelSelectionTest : public LabelTest { | 162 class LabelSelectionTest : public LabelTest { |
151 public: | 163 public: |
| 164 // Alias this long identifier for more readable tests. |
| 165 static constexpr bool kExtends = |
| 166 gfx::RenderText::kDragToEndIfOutsideVerticalBounds; |
| 167 |
| 168 // Some tests use cardinal directions to index an array of points above and |
| 169 // below the label in either visual direction. |
| 170 enum { NW, NORTH, NE, SE, SOUTH, SW }; |
| 171 |
152 LabelSelectionTest() {} | 172 LabelSelectionTest() {} |
153 | 173 |
154 // LabelTest overrides: | 174 // LabelTest overrides: |
155 void SetUp() override { | 175 void SetUp() override { |
156 #if defined(OS_MACOSX) | 176 #if defined(OS_MACOSX) |
157 // On Mac, by default RenderTextMac is used for labels which does not | 177 // On Mac, by default RenderTextMac is used for labels which does not |
158 // support text selection. Instead use RenderTextHarfBuzz for selection | 178 // support text selection. Instead use RenderTextHarfBuzz for selection |
159 // related tests. TODO(crbug.com/661394): Remove this once Mac also uses | 179 // related tests. TODO(crbug.com/661394): Remove this once Mac also uses |
160 // RenderTextHarfBuzz for Labels. | 180 // RenderTextHarfBuzz for Labels. |
161 base::CommandLine::ForCurrentProcess()->AppendSwitch( | 181 base::CommandLine::ForCurrentProcess()->AppendSwitch( |
(...skipping 865 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1027 | 1047 |
1028 PerformMouseDragTo(GetCursorPoint(7)); | 1048 PerformMouseDragTo(GetCursorPoint(7)); |
1029 EXPECT_STR_EQ("cd\nef", GetSelectedText()); | 1049 EXPECT_STR_EQ("cd\nef", GetSelectedText()); |
1030 | 1050 |
1031 PerformMouseDragTo(gfx::Point(-5, GetCursorPoint(6).y())); | 1051 PerformMouseDragTo(gfx::Point(-5, GetCursorPoint(6).y())); |
1032 EXPECT_STR_EQ("cd\n", GetSelectedText()); | 1052 EXPECT_STR_EQ("cd\n", GetSelectedText()); |
1033 | 1053 |
1034 PerformMouseDragTo(gfx::Point(100, GetCursorPoint(6).y())); | 1054 PerformMouseDragTo(gfx::Point(100, GetCursorPoint(6).y())); |
1035 EXPECT_STR_EQ("cd\nefgh", GetSelectedText()); | 1055 EXPECT_STR_EQ("cd\nefgh", GetSelectedText()); |
1036 | 1056 |
1037 PerformMouseDragTo(gfx::Point(GetCursorPoint(3).x(), -5)); | 1057 const gfx::Point points[] = { |
1038 EXPECT_STR_EQ(gfx::RenderText::kDragToEndIfOutsideVerticalBounds ? "ab" : "c", | 1058 {GetCursorPoint(1).x(), -5}, // NW. |
1039 GetSelectedText()); | 1059 {GetCursorPoint(2).x(), -5}, // NORTH. |
| 1060 {GetCursorPoint(3).x(), -5}, // NE. |
| 1061 {GetCursorPoint(8).x(), 100}, // SE. |
| 1062 {GetCursorPoint(7).x(), 100}, // SOUTH. |
| 1063 {GetCursorPoint(6).x(), 100}, // SW. |
| 1064 }; |
| 1065 constexpr const char* kExtendLeft = "ab"; |
| 1066 constexpr const char* kExtendRight = "cd\nefgh"; |
1040 | 1067 |
1041 PerformMouseDragTo(gfx::Point(GetCursorPoint(7).x(), 100)); | 1068 // For multiline, N* extends left, S* extends right. |
1042 EXPECT_STR_EQ(gfx::RenderText::kDragToEndIfOutsideVerticalBounds ? "cd\nefgh" | 1069 PerformMouseDragTo(points[NW]); |
1043 : "cd\nef", | 1070 EXPECT_STR_EQ(kExtends ? kExtendLeft : "b", GetSelectedText()); |
1044 GetSelectedText()); | 1071 PerformMouseDragTo(points[NORTH]); |
| 1072 EXPECT_STR_EQ(kExtends ? kExtendLeft : "", GetSelectedText()); |
| 1073 PerformMouseDragTo(points[NE]); |
| 1074 EXPECT_STR_EQ(kExtends ? kExtendLeft : "c", GetSelectedText()); |
| 1075 PerformMouseDragTo(points[SE]); |
| 1076 EXPECT_STR_EQ(kExtends ? kExtendRight : "cd\nefg", GetSelectedText()); |
| 1077 PerformMouseDragTo(points[SOUTH]); |
| 1078 EXPECT_STR_EQ(kExtends ? kExtendRight : "cd\nef", GetSelectedText()); |
| 1079 PerformMouseDragTo(points[SW]); |
| 1080 EXPECT_STR_EQ(kExtends ? kExtendRight : "cd\ne", GetSelectedText()); |
| 1081 } |
| 1082 |
| 1083 // Single line fields consider the x offset as well. Ties go to the right. |
| 1084 TEST_F(LabelSelectionTest, MouseDragSingleLineLTR) { |
| 1085 label()->SetText(ASCIIToUTF16("abcdef")); |
| 1086 label()->SizeToPreferredSize(); |
| 1087 ASSERT_TRUE(label()->SetSelectable(true)); |
| 1088 PerformMousePress(GetCursorPoint(2)); |
| 1089 const gfx::Point points[] = { |
| 1090 {GetCursorPoint(1).x(), -5}, // NW. |
| 1091 {GetCursorPoint(2).x(), -5}, // NORTH. |
| 1092 {GetCursorPoint(3).x(), -5}, // NE. |
| 1093 {GetCursorPoint(3).x(), 100}, // SE. |
| 1094 {GetCursorPoint(2).x(), 100}, // SOUTH. |
| 1095 {GetCursorPoint(1).x(), 100}, // SW. |
| 1096 }; |
| 1097 constexpr const char* kExtendLeft = "ab"; |
| 1098 constexpr const char* kExtendRight = "cdef"; |
| 1099 |
| 1100 // For single line, western directions extend left, all others extend right. |
| 1101 PerformMouseDragTo(points[NW]); |
| 1102 EXPECT_STR_EQ(kExtends ? kExtendLeft : "b", GetSelectedText()); |
| 1103 PerformMouseDragTo(points[NORTH]); |
| 1104 EXPECT_STR_EQ(kExtends ? kExtendRight : "", GetSelectedText()); |
| 1105 PerformMouseDragTo(points[NE]); |
| 1106 EXPECT_STR_EQ(kExtends ? kExtendRight : "c", GetSelectedText()); |
| 1107 PerformMouseDragTo(points[SE]); |
| 1108 EXPECT_STR_EQ(kExtends ? kExtendRight : "c", GetSelectedText()); |
| 1109 PerformMouseDragTo(points[SOUTH]); |
| 1110 EXPECT_STR_EQ(kExtends ? kExtendRight : "", GetSelectedText()); |
| 1111 PerformMouseDragTo(points[SW]); |
| 1112 EXPECT_STR_EQ(kExtends ? kExtendLeft : "b", GetSelectedText()); |
1045 } | 1113 } |
1046 | 1114 |
1047 TEST_F(LabelSelectionTest, MouseDragMultilineRTL) { | 1115 TEST_F(LabelSelectionTest, MouseDragMultilineRTL) { |
1048 label()->SetMultiLine(true); | 1116 label()->SetMultiLine(true); |
1049 label()->SetText(WideToUTF16(L"\x5d0\x5d1\x5d2\n\x5d3\x5d4\x5d5")); | 1117 label()->SetText(ToRTL("012\n345")); |
| 1118 // Sanity check. |
| 1119 EXPECT_EQ(WideToUTF16(L"\x5d0\x5d1\x5d2\n\x5d3\x5d4\x5d5"), label()->text()); |
| 1120 |
1050 label()->SizeToPreferredSize(); | 1121 label()->SizeToPreferredSize(); |
1051 ASSERT_TRUE(label()->SetSelectable(true)); | 1122 ASSERT_TRUE(label()->SetSelectable(true)); |
1052 ASSERT_EQ(2u, GetLineCount()); | 1123 ASSERT_EQ(2u, GetLineCount()); |
1053 | 1124 |
1054 PerformMousePress(GetCursorPoint(1)); | 1125 PerformMousePress(GetCursorPoint(1)); // Note: RTL drag starts at 1, not 2. |
1055 PerformMouseDragTo(GetCursorPoint(0)); | 1126 PerformMouseDragTo(GetCursorPoint(0)); |
1056 EXPECT_EQ(WideToUTF16(L"\x5d0"), GetSelectedText()); | 1127 EXPECT_EQ(ToRTL("0"), GetSelectedText()); |
1057 | 1128 |
1058 PerformMouseDragTo(GetCursorPoint(6)); | 1129 PerformMouseDragTo(GetCursorPoint(6)); |
1059 EXPECT_EQ(WideToUTF16(L"\x5d1\x5d2\n\x5d3\x5d4"), GetSelectedText()); | 1130 EXPECT_EQ(ToRTL("12\n34"), GetSelectedText()); |
1060 | 1131 |
1061 PerformMouseDragTo(gfx::Point(-5, GetCursorPoint(6).y())); | 1132 PerformMouseDragTo(gfx::Point(-5, GetCursorPoint(6).y())); |
1062 EXPECT_EQ(WideToUTF16(L"\x5d1\x5d2\n\x5d3\x5d4\x5d5"), GetSelectedText()); | 1133 EXPECT_EQ(ToRTL("12\n345"), GetSelectedText()); |
1063 | 1134 |
1064 PerformMouseDragTo(gfx::Point(100, GetCursorPoint(6).y())); | 1135 PerformMouseDragTo(gfx::Point(100, GetCursorPoint(6).y())); |
1065 EXPECT_EQ(WideToUTF16(L"\x5d1\x5d2\n"), GetSelectedText()); | 1136 EXPECT_EQ(ToRTL("12\n"), GetSelectedText()); |
1066 | 1137 |
1067 PerformMouseDragTo(gfx::Point(GetCursorPoint(2).x(), -5)); | 1138 const gfx::Point points[] = { |
1068 EXPECT_EQ(gfx::RenderText::kDragToEndIfOutsideVerticalBounds | 1139 {GetCursorPoint(2).x(), -5}, // NW: Now towards the end of the string. |
1069 ? WideToUTF16(L"\x5d0") | 1140 {GetCursorPoint(1).x(), -5}, // NORTH, |
1070 : WideToUTF16(L"\x5d1"), | 1141 {GetCursorPoint(0).x(), -5}, // NE: Towards the start. |
1071 GetSelectedText()); | 1142 {GetCursorPoint(4).x(), 100}, // SE. |
| 1143 {GetCursorPoint(5).x(), 100}, // SOUTH. |
| 1144 {GetCursorPoint(6).x(), 100}, // SW. |
| 1145 }; |
1072 | 1146 |
1073 PerformMouseDragTo(gfx::Point(GetCursorPoint(6).x(), 100)); | 1147 // Visual right, so to the beginning of the string for RTL. |
1074 EXPECT_EQ(gfx::RenderText::kDragToEndIfOutsideVerticalBounds | 1148 const base::string16 extend_right = ToRTL("0"); |
1075 ? WideToUTF16(L"\x5d1\x5d2\n\x5d3\x5d4\x5d5") | 1149 const base::string16 extend_left = ToRTL("12\n345"); |
1076 : WideToUTF16(L"\x5d1\x5d2\n\x5d3\x5d4"), | 1150 |
1077 GetSelectedText()); | 1151 // For multiline, N* extends right, S* extends left. |
| 1152 PerformMouseDragTo(points[NW]); |
| 1153 EXPECT_EQ(kExtends ? extend_right : ToRTL("1"), GetSelectedText()); |
| 1154 PerformMouseDragTo(points[NORTH]); |
| 1155 EXPECT_EQ(kExtends ? extend_right : ToRTL(""), GetSelectedText()); |
| 1156 PerformMouseDragTo(points[NE]); |
| 1157 EXPECT_EQ(kExtends ? extend_right : ToRTL("0"), GetSelectedText()); |
| 1158 PerformMouseDragTo(points[SE]); |
| 1159 EXPECT_EQ(kExtends ? extend_left : ToRTL("12\n"), GetSelectedText()); |
| 1160 PerformMouseDragTo(points[SOUTH]); |
| 1161 EXPECT_EQ(kExtends ? extend_left : ToRTL("12\n3"), GetSelectedText()); |
| 1162 PerformMouseDragTo(points[SW]); |
| 1163 EXPECT_EQ(kExtends ? extend_left : ToRTL("12\n34"), GetSelectedText()); |
| 1164 } |
| 1165 |
| 1166 TEST_F(LabelSelectionTest, MouseDragSingleLineRTL) { |
| 1167 label()->SetText(ToRTL("0123456")); |
| 1168 label()->SizeToPreferredSize(); |
| 1169 ASSERT_TRUE(label()->SetSelectable(true)); |
| 1170 |
| 1171 PerformMousePress(GetCursorPoint(1)); |
| 1172 const gfx::Point points[] = { |
| 1173 {GetCursorPoint(2).x(), -5}, // NW. |
| 1174 {GetCursorPoint(1).x(), -5}, // NORTH. |
| 1175 {GetCursorPoint(0).x(), -5}, // NE. |
| 1176 {GetCursorPoint(0).x(), 100}, // SE. |
| 1177 {GetCursorPoint(1).x(), 100}, // SOUTH. |
| 1178 {GetCursorPoint(2).x(), 100}, // SW. |
| 1179 }; |
| 1180 |
| 1181 // Visual right, so to the beginning of the string for RTL. |
| 1182 const base::string16 extend_right = ToRTL("0"); |
| 1183 const base::string16 extend_left = ToRTL("123456"); |
| 1184 |
| 1185 // For single line, western directions extend left, all others extend right. |
| 1186 PerformMouseDragTo(points[NW]); |
| 1187 EXPECT_EQ(kExtends ? extend_left : ToRTL("1"), GetSelectedText()); |
| 1188 PerformMouseDragTo(points[NORTH]); |
| 1189 EXPECT_EQ(kExtends ? extend_right : ToRTL(""), GetSelectedText()); |
| 1190 PerformMouseDragTo(points[NE]); |
| 1191 EXPECT_EQ(kExtends ? extend_right : ToRTL("0"), GetSelectedText()); |
| 1192 PerformMouseDragTo(points[SE]); |
| 1193 EXPECT_EQ(kExtends ? extend_right : ToRTL("0"), GetSelectedText()); |
| 1194 PerformMouseDragTo(points[SOUTH]); |
| 1195 EXPECT_EQ(kExtends ? extend_right : ToRTL(""), GetSelectedText()); |
| 1196 PerformMouseDragTo(points[SW]); |
| 1197 EXPECT_EQ(kExtends ? extend_left : ToRTL("1"), GetSelectedText()); |
1078 } | 1198 } |
1079 | 1199 |
1080 // Verify the initially selected word on a double click, remains selected on | 1200 // Verify the initially selected word on a double click, remains selected on |
1081 // mouse dragging. | 1201 // mouse dragging. |
1082 TEST_F(LabelSelectionTest, MouseDragWord) { | 1202 TEST_F(LabelSelectionTest, MouseDragWord) { |
1083 label()->SetText(ASCIIToUTF16("Label drag word")); | 1203 label()->SetText(ASCIIToUTF16("Label drag word")); |
1084 label()->SizeToPreferredSize(); | 1204 label()->SizeToPreferredSize(); |
1085 ASSERT_TRUE(label()->SetSelectable(true)); | 1205 ASSERT_TRUE(label()->SetSelectable(true)); |
1086 | 1206 |
1087 PerformClick(GetCursorPoint(8)); | 1207 PerformClick(GetCursorPoint(8)); |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1188 EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_SELECT_ALL)); | 1308 EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_SELECT_ALL)); |
1189 } | 1309 } |
1190 | 1310 |
1191 INSTANTIATE_TEST_CASE_P(, | 1311 INSTANTIATE_TEST_CASE_P(, |
1192 MDLabelTest, | 1312 MDLabelTest, |
1193 ::testing::Values(SecondaryUiMode::MD, | 1313 ::testing::Values(SecondaryUiMode::MD, |
1194 SecondaryUiMode::NON_MD), | 1314 SecondaryUiMode::NON_MD), |
1195 &SecondaryUiModeToString); | 1315 &SecondaryUiModeToString); |
1196 | 1316 |
1197 } // namespace views | 1317 } // namespace views |
OLD | NEW |