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/gfx/render_text.h" | 5 #include "ui/gfx/render_text.h" |
6 | 6 |
7 #include "base/memory/scoped_ptr.h" | 7 #include "base/memory/scoped_ptr.h" |
8 #include "base/utf_string_conversions.h" | 8 #include "base/utf_string_conversions.h" |
9 #include "testing/gtest/include/gtest/gtest.h" | 9 #include "testing/gtest/include/gtest/gtest.h" |
10 #include "ui/base/l10n/l10n_util.h" | 10 #include "ui/base/l10n/l10n_util.h" |
| 11 #include "ui/gfx/text_constants.h" |
11 | 12 |
12 #if defined(OS_WIN) | 13 #if defined(OS_WIN) |
13 #include "base/win/windows_version.h" | 14 #include "base/win/windows_version.h" |
14 #endif | 15 #endif |
15 | 16 |
16 #if defined(TOOLKIT_GTK) | 17 #if defined(TOOLKIT_GTK) |
17 #include <gtk/gtk.h> | 18 #include <gtk/gtk.h> |
18 #endif | 19 #endif |
19 | 20 |
20 namespace gfx { | 21 namespace gfx { |
21 | 22 |
22 namespace { | 23 namespace { |
23 | 24 |
| 25 // Various weak, LTR, RTL, and Bidi string cases with three characters each. |
| 26 const wchar_t kWeak[] = L" . "; |
| 27 const wchar_t kLtr[] = L"abc"; |
| 28 const wchar_t kLtrRtl[] = L"a"L"\x5d0\x5d1"; |
| 29 const wchar_t kLtrRtlLtr[] = L"a"L"\x5d1"L"b"; |
| 30 const wchar_t kRtl[] = L"\x5d0\x5d1\x5d2"; |
| 31 const wchar_t kRtlLtr[] = L"\x5d0\x5d1"L"a"; |
| 32 const wchar_t kRtlLtrRtl[] = L"\x5d0"L"a"L"\x5d1"; |
| 33 |
24 // Checks whether |range| contains |index|. This is not the same as calling | 34 // Checks whether |range| contains |index|. This is not the same as calling |
25 // |range.Contains(ui::Range(index))| - as that would return true when | 35 // |range.Contains(ui::Range(index))| - as that would return true when |
26 // |index| == |range.end()|. | 36 // |index| == |range.end()|. |
27 bool IndexInRange(const ui::Range& range, size_t index) { | 37 bool IndexInRange(const ui::Range& range, size_t index) { |
28 return index >= range.start() && index < range.end(); | 38 return index >= range.start() && index < range.end(); |
29 } | 39 } |
30 | 40 |
31 // A test utility function to set the application default text direction. | 41 // A test utility function to set the application default text direction. |
32 void SetRTL(bool rtl) { | 42 void SetRTL(bool rtl) { |
33 // Override the current locale/direction. | 43 // Override the current locale/direction. |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
212 EXPECT_EQ(ui::Range(2, 10), render_text->style_ranges()[1].range); | 222 EXPECT_EQ(ui::Range(2, 10), render_text->style_ranges()[1].range); |
213 EXPECT_EQ(SK_ColorRED, render_text->style_ranges()[1].foreground); | 223 EXPECT_EQ(SK_ColorRED, render_text->style_ranges()[1].foreground); |
214 EXPECT_EQ(ui::Range(10, 12), render_text->style_ranges()[2].range); | 224 EXPECT_EQ(ui::Range(10, 12), render_text->style_ranges()[2].range); |
215 EXPECT_TRUE(render_text->style_ranges()[2].underline); | 225 EXPECT_TRUE(render_text->style_ranges()[2].underline); |
216 EXPECT_TRUE(render_text->style_ranges()[2].strike); | 226 EXPECT_TRUE(render_text->style_ranges()[2].strike); |
217 } | 227 } |
218 | 228 |
219 static void SetTextWith2ExtraStyles(RenderText* render_text) { | 229 static void SetTextWith2ExtraStyles(RenderText* render_text) { |
220 render_text->SetText(ASCIIToUTF16("abcdefghi")); | 230 render_text->SetText(ASCIIToUTF16("abcdefghi")); |
221 | 231 |
222 gfx::StyleRange strike; | 232 StyleRange strike; |
223 strike.strike = true; | 233 strike.strike = true; |
224 strike.range = ui::Range(0, 3); | 234 strike.range = ui::Range(0, 3); |
225 render_text->ApplyStyleRange(strike); | 235 render_text->ApplyStyleRange(strike); |
226 | 236 |
227 gfx::StyleRange underline; | 237 StyleRange underline; |
228 underline.underline = true; | 238 underline.underline = true; |
229 underline.range = ui::Range(3, 6); | 239 underline.range = ui::Range(3, 6); |
230 render_text->ApplyStyleRange(underline); | 240 render_text->ApplyStyleRange(underline); |
231 } | 241 } |
232 | 242 |
233 TEST_F(RenderTextTest, StyleRangesAdjust) { | 243 TEST_F(RenderTextTest, StyleRangesAdjust) { |
234 // Test that style ranges adjust to the text size. | 244 // Test that style ranges adjust to the text size. |
235 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | 245 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
236 render_text->SetText(ASCIIToUTF16("abcdef")); | 246 render_text->SetText(ASCIIToUTF16("abcdef")); |
237 EXPECT_EQ(1U, render_text->style_ranges().size()); | 247 EXPECT_EQ(1U, render_text->style_ranges().size()); |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 }; | 386 }; |
377 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(texts); ++i) { | 387 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(texts); ++i) { |
378 string16 text = WideToUTF16(texts[i]); | 388 string16 text = WideToUTF16(texts[i]); |
379 TestVisualCursorMotionInObscuredField(render_text.get(), text, false); | 389 TestVisualCursorMotionInObscuredField(render_text.get(), text, false); |
380 TestVisualCursorMotionInObscuredField(render_text.get(), text, true); | 390 TestVisualCursorMotionInObscuredField(render_text.get(), text, true); |
381 } | 391 } |
382 #endif // !defined(OS_WIN) | 392 #endif // !defined(OS_WIN) |
383 } | 393 } |
384 | 394 |
385 TEST_F(RenderTextTest, GetTextDirection) { | 395 TEST_F(RenderTextTest, GetTextDirection) { |
| 396 struct { |
| 397 const wchar_t* text; |
| 398 const base::i18n::TextDirection text_direction; |
| 399 } cases[] = { |
| 400 // Blank strings and those with no/weak directionality default to LTR. |
| 401 { L"", base::i18n::LEFT_TO_RIGHT }, |
| 402 { kWeak, base::i18n::LEFT_TO_RIGHT }, |
| 403 // Strings that begin with strong LTR characters. |
| 404 { kLtr, base::i18n::LEFT_TO_RIGHT }, |
| 405 { kLtrRtl, base::i18n::LEFT_TO_RIGHT }, |
| 406 { kLtrRtlLtr, base::i18n::LEFT_TO_RIGHT }, |
| 407 // Strings that begin with strong RTL characters. |
| 408 { kRtl, base::i18n::RIGHT_TO_LEFT }, |
| 409 { kRtlLtr, base::i18n::RIGHT_TO_LEFT }, |
| 410 { kRtlLtrRtl, base::i18n::RIGHT_TO_LEFT }, |
| 411 }; |
| 412 |
| 413 // Ensure that directionality modes yield the correct text directions. |
| 414 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
386 const bool was_rtl = base::i18n::IsRTL(); | 415 const bool was_rtl = base::i18n::IsRTL(); |
387 // Ensure that text direction is set by the first strong character direction. | 416 |
388 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | |
389 for (size_t i = 0; i < 2; ++i) { | 417 for (size_t i = 0; i < 2; ++i) { |
390 // Toggle the application default text direction (to try each direction). | 418 // Toggle the application default text direction (to try each direction). |
391 SetRTL(!base::i18n::IsRTL()); | 419 SetRTL(!base::i18n::IsRTL()); |
| 420 const base::i18n::TextDirection ui_direction = base::i18n::IsRTL() ? |
| 421 base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT; |
392 | 422 |
393 // Blank strings (and those without directionality) default to LTR. | 423 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(cases); j++) { |
394 render_text->SetText(string16()); | 424 render_text->SetText(WideToUTF16(cases[j].text)); |
395 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, render_text->GetTextDirection()); | 425 render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_TEXT); |
396 render_text->SetText(ASCIIToUTF16(" ")); | 426 EXPECT_EQ(render_text->GetTextDirection(), cases[j].text_direction); |
397 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, render_text->GetTextDirection()); | 427 render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_UI); |
| 428 EXPECT_EQ(render_text->GetTextDirection(), ui_direction); |
| 429 render_text->SetDirectionalityMode(DIRECTIONALITY_FORCE_LTR); |
| 430 EXPECT_EQ(render_text->GetTextDirection(), base::i18n::LEFT_TO_RIGHT); |
| 431 render_text->SetDirectionalityMode(DIRECTIONALITY_FORCE_RTL); |
| 432 EXPECT_EQ(render_text->GetTextDirection(), base::i18n::RIGHT_TO_LEFT); |
| 433 } |
| 434 } |
398 | 435 |
399 // Pure LTR. | |
400 render_text->SetText(ASCIIToUTF16("abc")); | |
401 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, render_text->GetTextDirection()); | |
402 // LTR-RTL | |
403 render_text->SetText(WideToUTF16(L"abc\x05d0\x05d1\x05d2")); | |
404 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, render_text->GetTextDirection()); | |
405 // LTR-RTL-LTR. | |
406 render_text->SetText(WideToUTF16(L"a"L"\x05d1"L"b")); | |
407 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, render_text->GetTextDirection()); | |
408 // Pure RTL. | |
409 render_text->SetText(WideToUTF16(L"\x05d0\x05d1\x05d2")); | |
410 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, render_text->GetTextDirection()); | |
411 // RTL-LTR | |
412 render_text->SetText(WideToUTF16(L"\x05d0\x05d1\x05d2"L"abc")); | |
413 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, render_text->GetTextDirection()); | |
414 // RTL-LTR-RTL. | |
415 render_text->SetText(WideToUTF16(L"\x05d0"L"a"L"\x05d1")); | |
416 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, render_text->GetTextDirection()); | |
417 } | |
418 EXPECT_EQ(was_rtl, base::i18n::IsRTL()); | 436 EXPECT_EQ(was_rtl, base::i18n::IsRTL()); |
419 } | 437 } |
420 | 438 |
421 void RunMoveCursorLeftRightTest(RenderText* render_text, | 439 void RunMoveCursorLeftRightTest(RenderText* render_text, |
422 const std::vector<SelectionModel>& expected, | 440 const std::vector<SelectionModel>& expected, |
423 VisualCursorDirection direction) { | 441 VisualCursorDirection direction) { |
424 for (size_t i = 0; i < expected.size(); ++i) { | 442 for (size_t i = 0; i < expected.size(); ++i) { |
425 EXPECT_EQ(expected[i], render_text->selection_model()); | 443 EXPECT_EQ(expected[i], render_text->selection_model()); |
426 render_text->MoveCursor(CHARACTER_BREAK, direction, false); | 444 render_text->MoveCursor(CHARACTER_BREAK, direction, false); |
427 } | 445 } |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
724 render_text->EdgeSelectionModel(ltr ? CURSOR_LEFT : CURSOR_RIGHT); | 742 render_text->EdgeSelectionModel(ltr ? CURSOR_LEFT : CURSOR_RIGHT); |
725 EXPECT_EQ(start_edge, SelectionModel(0, CURSOR_BACKWARD)); | 743 EXPECT_EQ(start_edge, SelectionModel(0, CURSOR_BACKWARD)); |
726 | 744 |
727 SelectionModel end_edge = | 745 SelectionModel end_edge = |
728 render_text->EdgeSelectionModel(ltr ? CURSOR_RIGHT : CURSOR_LEFT); | 746 render_text->EdgeSelectionModel(ltr ? CURSOR_RIGHT : CURSOR_LEFT); |
729 EXPECT_EQ(end_edge, SelectionModel(cases[i].text.length(), CURSOR_FORWARD)); | 747 EXPECT_EQ(end_edge, SelectionModel(cases[i].text.length(), CURSOR_FORWARD)); |
730 } | 748 } |
731 } | 749 } |
732 | 750 |
733 TEST_F(RenderTextTest, SelectAll) { | 751 TEST_F(RenderTextTest, SelectAll) { |
734 const wchar_t* const cases[] = { | 752 const wchar_t* const cases[] = |
735 L"abc", | 753 { kWeak, kLtr, kLtrRtl, kLtrRtlLtr, kRtl, kRtlLtr, kRtlLtrRtl }; |
736 L"a"L"\x5d0\x5d1", | |
737 L"a"L"\x5d1"L"b", | |
738 L"\x5d0\x5d1\x5d2", | |
739 L"\x5d0\x5d1"L"a", | |
740 L"\x5d0"L"a"L"\x5d1", | |
741 }; | |
742 | 754 |
743 // Ensure that SelectAll respects the |reversed| argument regardless of | 755 // Ensure that SelectAll respects the |reversed| argument regardless of |
744 // application locale and text content directionality. | 756 // application locale and text content directionality. |
745 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); | 757 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); |
746 const SelectionModel expected_reversed(ui::Range(3, 0), CURSOR_FORWARD); | 758 const SelectionModel expected_reversed(ui::Range(3, 0), CURSOR_FORWARD); |
747 const SelectionModel expected_forwards(ui::Range(0, 3), CURSOR_BACKWARD); | 759 const SelectionModel expected_forwards(ui::Range(0, 3), CURSOR_BACKWARD); |
748 const bool was_rtl = base::i18n::IsRTL(); | 760 const bool was_rtl = base::i18n::IsRTL(); |
749 | 761 |
750 for (size_t i = 0; i < 2; ++i) { | 762 for (size_t i = 0; i < 2; ++i) { |
751 SetRTL(!base::i18n::IsRTL()); | 763 SetRTL(!base::i18n::IsRTL()); |
| 764 // Test that an empty string produces an empty selection model. |
| 765 render_text->SetText(string16()); |
| 766 EXPECT_EQ(render_text->selection_model(), SelectionModel()); |
| 767 |
| 768 // Test the weak, LTR, RTL, and Bidi string cases. |
752 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(cases); j++) { | 769 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(cases); j++) { |
753 render_text->SetText(WideToUTF16(cases[j])); | 770 render_text->SetText(WideToUTF16(cases[j])); |
754 render_text->SelectAll(false); | 771 render_text->SelectAll(false); |
755 EXPECT_EQ(render_text->selection_model(), expected_forwards); | 772 EXPECT_EQ(render_text->selection_model(), expected_forwards); |
756 render_text->SelectAll(true); | 773 render_text->SelectAll(true); |
757 EXPECT_EQ(render_text->selection_model(), expected_reversed); | 774 EXPECT_EQ(render_text->selection_model(), expected_reversed); |
758 } | 775 } |
759 } | 776 } |
760 | 777 |
761 EXPECT_EQ(was_rtl, base::i18n::IsRTL()); | 778 EXPECT_EQ(was_rtl, base::i18n::IsRTL()); |
(...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1273 EXPECT_EQ(render_text->display_rect().width() - width - 1, | 1290 EXPECT_EQ(render_text->display_rect().width() - width - 1, |
1274 render_text->GetUpdatedCursorBounds().x()); | 1291 render_text->GetUpdatedCursorBounds().x()); |
1275 | 1292 |
1276 // Reset the application default text direction to LTR. | 1293 // Reset the application default text direction to LTR. |
1277 SetRTL(was_rtl); | 1294 SetRTL(was_rtl); |
1278 EXPECT_EQ(was_rtl, base::i18n::IsRTL()); | 1295 EXPECT_EQ(was_rtl, base::i18n::IsRTL()); |
1279 } | 1296 } |
1280 #endif // !defined(OS_MACOSX) | 1297 #endif // !defined(OS_MACOSX) |
1281 | 1298 |
1282 } // namespace gfx | 1299 } // namespace gfx |
OLD | NEW |