OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "core/editing/InputMethodController.h" | 5 #include "core/editing/InputMethodController.h" |
6 | 6 |
7 #include "core/dom/Document.h" | 7 #include "core/dom/Document.h" |
8 #include "core/dom/Element.h" | 8 #include "core/dom/Element.h" |
9 #include "core/dom/Range.h" | 9 #include "core/dom/Range.h" |
10 #include "core/editing/Editor.h" | 10 #include "core/editing/Editor.h" |
(...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
679 EXPECT_STREQ("aaa\nbbbddd\neee", div->innerText().utf8().data()); | 679 EXPECT_STREQ("aaa\nbbbddd\neee", div->innerText().utf8().data()); |
680 EXPECT_EQ(7u, controller().getSelectionOffsets().start()); | 680 EXPECT_EQ(7u, controller().getSelectionOffsets().start()); |
681 EXPECT_EQ(7u, controller().getSelectionOffsets().end()); | 681 EXPECT_EQ(7u, controller().getSelectionOffsets().end()); |
682 | 682 |
683 controller().deleteSurroundingText(5, 5); | 683 controller().deleteSurroundingText(5, 5); |
684 EXPECT_STREQ("aaee", div->innerText().utf8().data()); | 684 EXPECT_STREQ("aaee", div->innerText().utf8().data()); |
685 EXPECT_EQ(2u, controller().getSelectionOffsets().start()); | 685 EXPECT_EQ(2u, controller().getSelectionOffsets().start()); |
686 EXPECT_EQ(2u, controller().getSelectionOffsets().end()); | 686 EXPECT_EQ(2u, controller().getSelectionOffsets().end()); |
687 } | 687 } |
688 | 688 |
| 689 TEST_F(InputMethodControllerTest, DeleteSurroundingTextInCodePoints) { |
| 690 HTMLInputElement* input = |
| 691 toHTMLInputElement(insertHTMLElement("<input id='sample'>", "sample")); |
| 692 |
| 693 input->setValue("abc123"); |
| 694 document().updateStyleAndLayout(); |
| 695 controller().setEditableSelectionOffsets(PlainTextRange(3, 3)); |
| 696 EXPECT_STREQ("abc123", input->value().utf8().data()); |
| 697 |
| 698 controller().deleteSurroundingTextInCodePoints(0, 0); |
| 699 EXPECT_STREQ("abc123", input->value().utf8().data()); |
| 700 |
| 701 controller().deleteSurroundingTextInCodePoints(1, 0); |
| 702 EXPECT_STREQ("ab123", input->value().utf8().data()); |
| 703 |
| 704 // Exceeds left boundary. |
| 705 controller().deleteSurroundingTextInCodePoints(10, 0); |
| 706 EXPECT_STREQ("123", input->value().utf8().data()); |
| 707 |
| 708 input->setValue("abc123"); |
| 709 document().updateStyleAndLayout(); |
| 710 controller().setEditableSelectionOffsets(PlainTextRange(3, 3)); |
| 711 EXPECT_STREQ("abc123", input->value().utf8().data()); |
| 712 |
| 713 controller().deleteSurroundingTextInCodePoints(0, 1); |
| 714 EXPECT_STREQ("abc23", input->value().utf8().data()); |
| 715 |
| 716 // Exceeds right boundary. |
| 717 controller().deleteSurroundingTextInCodePoints(0, 10); |
| 718 EXPECT_STREQ("abc", input->value().utf8().data()); |
| 719 |
| 720 input->setValue("abc123"); |
| 721 document().updateStyleAndLayout(); |
| 722 controller().setEditableSelectionOffsets(PlainTextRange(3, 3)); |
| 723 EXPECT_STREQ("abc123", input->value().utf8().data()); |
| 724 |
| 725 controller().deleteSurroundingTextInCodePoints(1, 2); |
| 726 EXPECT_STREQ("ab3", input->value().utf8().data()); |
| 727 |
| 728 // Exceeds both left and right boundary. |
| 729 controller().deleteSurroundingTextInCodePoints(10, 10); |
| 730 EXPECT_STREQ("", input->value().utf8().data()); |
| 731 } |
| 732 |
| 733 TEST_F(InputMethodControllerTest, |
| 734 DeleteSurroundingTextInCodePointsWithEmptyText) { |
| 735 HTMLInputElement* input = |
| 736 toHTMLInputElement(insertHTMLElement("<input id='sample'>", "sample")); |
| 737 |
| 738 input->setValue(""); |
| 739 document().updateStyleAndLayout(); |
| 740 EXPECT_STREQ("", input->value().utf8().data()); |
| 741 |
| 742 controller().deleteSurroundingTextInCodePoints(2, 2); |
| 743 EXPECT_STREQ("", input->value().utf8().data()); |
| 744 } |
| 745 |
| 746 TEST_F(InputMethodControllerTest, |
| 747 DeleteSurroundingTextInCodePointsWithMultiCodeTextOnTheLeft) { |
| 748 HTMLInputElement* input = |
| 749 toHTMLInputElement(insertHTMLElement("<input id='sample'>", "sample")); |
| 750 |
| 751 // 'a' + "black star" + SPACE + "trophy" + SPACE + composed text (U+0E01 |
| 752 // "ka kai" + U+0E49 "mai tho"). |
| 753 // A "black star" is 1 grapheme cluster. It has 1 code point, and its length |
| 754 // is 1 (abbreviated as [1,1,1]). A "trophy": [1,1,2]. The composed text: |
| 755 // [1,2,2]. |
| 756 input->setValue(String::fromUTF8( |
| 757 "a\xE2\x98\x85 \xF0\x9F\x8F\x86 \xE0\xB8\x81\xE0\xB9\x89")); |
| 758 document().updateStyleAndLayout(); |
| 759 // The cursor is at the end of the text. |
| 760 controller().setEditableSelectionOffsets(PlainTextRange(8, 8)); |
| 761 |
| 762 controller().deleteSurroundingTextInCodePoints(2, 0); |
| 763 EXPECT_STREQ("a\xE2\x98\x85 \xF0\x9F\x8F\x86 ", input->value().utf8().data()); |
| 764 controller().deleteSurroundingTextInCodePoints(4, 0); |
| 765 EXPECT_STREQ("a", input->value().utf8().data()); |
| 766 |
| 767 // 'a' + "black star" + SPACE + "trophy" + SPACE + composed text |
| 768 input->setValue(String::fromUTF8( |
| 769 "a\xE2\x98\x85 \xF0\x9F\x8F\x86 \xE0\xB8\x81\xE0\xB9\x89")); |
| 770 document().updateStyleAndLayout(); |
| 771 // The cursor is at the end of the text. |
| 772 controller().setEditableSelectionOffsets(PlainTextRange(8, 8)); |
| 773 |
| 774 // TODO(yabinh): We should only delete 1 code point instead of the entire |
| 775 // grapheme cluster (2 code points). The root cause is that we adjust the |
| 776 // selection by grapheme cluster in deleteSurroundingText(). |
| 777 controller().deleteSurroundingTextInCodePoints(1, 0); |
| 778 EXPECT_STREQ("a\xE2\x98\x85 \xF0\x9F\x8F\x86 ", input->value().utf8().data()); |
| 779 } |
| 780 |
| 781 TEST_F(InputMethodControllerTest, |
| 782 DeleteSurroundingTextInCodePointsWithMultiCodeTextOnTheRight) { |
| 783 HTMLInputElement* input = |
| 784 toHTMLInputElement(insertHTMLElement("<input id='sample'>", "sample")); |
| 785 |
| 786 // 'a' + "black star" + SPACE + "trophy" + SPACE + composed text |
| 787 input->setValue(String::fromUTF8( |
| 788 "a\xE2\x98\x85 \xF0\x9F\x8F\x86 \xE0\xB8\x81\xE0\xB9\x89")); |
| 789 document().updateStyleAndLayout(); |
| 790 controller().setEditableSelectionOffsets(PlainTextRange(0, 0)); |
| 791 |
| 792 controller().deleteSurroundingTextInCodePoints(0, 5); |
| 793 EXPECT_STREQ("\xE0\xB8\x81\xE0\xB9\x89", input->value().utf8().data()); |
| 794 |
| 795 controller().deleteSurroundingTextInCodePoints(0, 1); |
| 796 // TODO(yabinh): Same here. We should only delete 1 code point. |
| 797 EXPECT_STREQ("", input->value().utf8().data()); |
| 798 } |
| 799 |
| 800 TEST_F(InputMethodControllerTest, |
| 801 DeleteSurroundingTextInCodePointsWithMultiCodeTextOnBothSides) { |
| 802 HTMLInputElement* input = |
| 803 toHTMLInputElement(insertHTMLElement("<input id='sample'>", "sample")); |
| 804 |
| 805 // 'a' + "black star" + SPACE + "trophy" + SPACE + composed text |
| 806 input->setValue(String::fromUTF8( |
| 807 "a\xE2\x98\x85 \xF0\x9F\x8F\x86 \xE0\xB8\x81\xE0\xB9\x89")); |
| 808 document().updateStyleAndLayout(); |
| 809 controller().setEditableSelectionOffsets(PlainTextRange(3, 3)); |
| 810 controller().deleteSurroundingTextInCodePoints(2, 2); |
| 811 EXPECT_STREQ("a\xE0\xB8\x81\xE0\xB9\x89", input->value().utf8().data()); |
| 812 } |
| 813 |
| 814 TEST_F(InputMethodControllerTest, |
| 815 DeleteSurroundingTextInCodePointsWithRangeSelection) { |
| 816 HTMLInputElement* input = |
| 817 toHTMLInputElement(insertHTMLElement("<input id='sample'>", "sample")); |
| 818 |
| 819 input->setValue("abc123"); |
| 820 document().updateStyleAndLayout(); |
| 821 controller().setEditableSelectionOffsets(PlainTextRange(2, 4)); |
| 822 EXPECT_STREQ("abc123", input->value().utf8().data()); |
| 823 |
| 824 controller().deleteSurroundingTextInCodePoints(1, 2); |
| 825 EXPECT_STREQ("ac1", input->value().utf8().data()); |
| 826 } |
| 827 |
| 828 TEST_F(InputMethodControllerTest, |
| 829 DeleteSurroundingTextInCodePointsForMultipleNodes) { |
| 830 Element* div = insertHTMLElement( |
| 831 "<div id='sample' contenteditable>aaa" |
| 832 "<div id='sample2' contenteditable>bbb" |
| 833 "<div id='sample3' contenteditable>ccc" |
| 834 "<div id='sample4' contenteditable>ddd" |
| 835 "<div id='sample5' contenteditable>eee" |
| 836 "</div></div></div></div></div>", |
| 837 "sample"); |
| 838 |
| 839 controller().setEditableSelectionOffsets(PlainTextRange(8, 8)); |
| 840 EXPECT_STREQ("aaa\nbbb\nccc\nddd\neee", div->innerText().utf8().data()); |
| 841 EXPECT_EQ(8u, controller().getSelectionOffsets().start()); |
| 842 EXPECT_EQ(8u, controller().getSelectionOffsets().end()); |
| 843 |
| 844 controller().deleteSurroundingTextInCodePoints(1, 0); |
| 845 EXPECT_STREQ("aaa\nbbbccc\nddd\neee", div->innerText().utf8().data()); |
| 846 EXPECT_EQ(7u, controller().getSelectionOffsets().start()); |
| 847 EXPECT_EQ(7u, controller().getSelectionOffsets().end()); |
| 848 |
| 849 controller().deleteSurroundingTextInCodePoints(0, 4); |
| 850 EXPECT_STREQ("aaa\nbbbddd\neee", div->innerText().utf8().data()); |
| 851 EXPECT_EQ(7u, controller().getSelectionOffsets().start()); |
| 852 EXPECT_EQ(7u, controller().getSelectionOffsets().end()); |
| 853 |
| 854 controller().deleteSurroundingTextInCodePoints(5, 5); |
| 855 EXPECT_STREQ("aaee", div->innerText().utf8().data()); |
| 856 EXPECT_EQ(2u, controller().getSelectionOffsets().start()); |
| 857 EXPECT_EQ(2u, controller().getSelectionOffsets().end()); |
| 858 } |
| 859 |
| 860 TEST_F(InputMethodControllerTest, DeleteSurroundingTextInCodePointsWithImage) { |
| 861 Element* div = insertHTMLElement( |
| 862 "<div id='sample' contenteditable>aaa" |
| 863 "<img src='empty.png'>bbb</div>", |
| 864 "sample"); |
| 865 |
| 866 controller().setEditableSelectionOffsets(PlainTextRange(4, 4)); |
| 867 controller().deleteSurroundingTextInCodePoints(1, 1); |
| 868 EXPECT_STREQ("aaabb", div->innerText().utf8().data()); |
| 869 EXPECT_EQ(3u, controller().getSelectionOffsets().start()); |
| 870 EXPECT_EQ(3u, controller().getSelectionOffsets().end()); |
| 871 } |
| 872 |
| 873 TEST_F(InputMethodControllerTest, |
| 874 DeleteSurroundingTextInCodePointsWithInvalidSurrogatePair) { |
| 875 HTMLInputElement* input = |
| 876 toHTMLInputElement(insertHTMLElement("<input id='sample'>", "sample")); |
| 877 |
| 878 // 'a' + high surrogate of "trophy" + "black star" + low surrogate of "trophy" |
| 879 // + SPACE |
| 880 const UChar UText[] = {'a', 0xD83C, 0x2605, 0xDFC6, ' ', '\0'}; |
| 881 const String& text = String(UText); |
| 882 |
| 883 input->setValue(text); |
| 884 document().updateStyleAndLayout(); |
| 885 // The invalid high surrogate is encoded as '\xED\xA0\xBC', and invalid low |
| 886 // surrogate is encoded as '\xED\xBF\x86'. |
| 887 EXPECT_STREQ("a\xED\xA0\xBC\xE2\x98\x85\xED\xBF\x86 ", |
| 888 input->value().utf8().data()); |
| 889 |
| 890 controller().setEditableSelectionOffsets(PlainTextRange(5, 5)); |
| 891 // Delete a SPACE. |
| 892 controller().deleteSurroundingTextInCodePoints(1, 0); |
| 893 EXPECT_STREQ("a\xED\xA0\xBC\xE2\x98\x85\xED\xBF\x86", |
| 894 input->value().utf8().data()); |
| 895 // Do nothing since there is an invalid surrogate in the requested range. |
| 896 controller().deleteSurroundingTextInCodePoints(2, 0); |
| 897 EXPECT_STREQ("a\xED\xA0\xBC\xE2\x98\x85\xED\xBF\x86", |
| 898 input->value().utf8().data()); |
| 899 |
| 900 controller().setEditableSelectionOffsets(PlainTextRange(0, 0)); |
| 901 // Delete 'a'. |
| 902 controller().deleteSurroundingTextInCodePoints(0, 1); |
| 903 EXPECT_STREQ("\xED\xA0\xBC\xE2\x98\x85\xED\xBF\x86", |
| 904 input->value().utf8().data()); |
| 905 // Do nothing since there is an invalid surrogate in the requested range. |
| 906 controller().deleteSurroundingTextInCodePoints(0, 2); |
| 907 EXPECT_STREQ("\xED\xA0\xBC\xE2\x98\x85\xED\xBF\x86", |
| 908 input->value().utf8().data()); |
| 909 } |
| 910 |
689 TEST_F(InputMethodControllerTest, SetCompositionForInputWithNewCaretPositions) { | 911 TEST_F(InputMethodControllerTest, SetCompositionForInputWithNewCaretPositions) { |
690 HTMLInputElement* input = | 912 HTMLInputElement* input = |
691 toHTMLInputElement(insertHTMLElement("<input id='sample'>", "sample")); | 913 toHTMLInputElement(insertHTMLElement("<input id='sample'>", "sample")); |
692 | 914 |
693 input->setValue("hello"); | 915 input->setValue("hello"); |
694 document().updateStyleAndLayout(); | 916 document().updateStyleAndLayout(); |
695 controller().setEditableSelectionOffsets(PlainTextRange(2, 2)); | 917 controller().setEditableSelectionOffsets(PlainTextRange(2, 2)); |
696 EXPECT_STREQ("hello", input->value().utf8().data()); | 918 EXPECT_STREQ("hello", input->value().utf8().data()); |
697 EXPECT_EQ(2u, controller().getSelectionOffsets().start()); | 919 EXPECT_EQ(2u, controller().getSelectionOffsets().start()); |
698 EXPECT_EQ(2u, controller().getSelectionOffsets().end()); | 920 EXPECT_EQ(2u, controller().getSelectionOffsets().end()); |
(...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1140 EXPECT_EQ(WebTextInputTypeNone, controller().textInputType()); | 1362 EXPECT_EQ(WebTextInputTypeNone, controller().textInputType()); |
1141 | 1363 |
1142 document().getElementById("b")->focus(); | 1364 document().getElementById("b")->focus(); |
1143 EXPECT_EQ(WebTextInputTypeTelephone, controller().textInputType()); | 1365 EXPECT_EQ(WebTextInputTypeTelephone, controller().textInputType()); |
1144 | 1366 |
1145 controller().finishComposingText(InputMethodController::KeepSelection); | 1367 controller().finishComposingText(InputMethodController::KeepSelection); |
1146 EXPECT_EQ(WebTextInputTypeTelephone, controller().textInputType()); | 1368 EXPECT_EQ(WebTextInputTypeTelephone, controller().textInputType()); |
1147 } | 1369 } |
1148 | 1370 |
1149 } // namespace blink | 1371 } // namespace blink |
OLD | NEW |