diff options
-rw-r--r-- | components/script/textinput.rs | 16 | ||||
-rw-r--r-- | tests/unit/script/textinput.rs | 9 |
2 files changed, 22 insertions, 3 deletions
diff --git a/components/script/textinput.rs b/components/script/textinput.rs index cc5936d42b0..ec4af672178 100644 --- a/components/script/textinput.rs +++ b/components/script/textinput.rs @@ -107,6 +107,16 @@ fn is_printable_key(key: Key) -> bool { } } +/// The length in bytes of the first n characters in a UTF-8 string. +/// +/// If the string has fewer than n characters, returns the length of the whole string. +fn len_of_first_n_chars(text: &str, n: usize) -> usize { + match text.char_indices().take(n).last() { + Some((index, ch)) => index + ch.len_utf8(), + None => 0 + } +} + impl<T: ClipboardProvider> TextInput<T> { /// Instantiate a new text input control pub fn new(lines: Lines, initial: DOMString, clipboard_provider: T, max_length: Option<usize>) -> TextInput<T> { @@ -213,8 +223,8 @@ impl<T: ClipboardProvider> TextInput<T> { usize::MAX }; - let last_char_to_insert = min(allowed_to_insert_count, insert.chars().count()); - let chars_to_insert = (&insert[0 .. last_char_to_insert]).to_owned(); + let last_char_index = len_of_first_n_chars(&*insert, allowed_to_insert_count); + let chars_to_insert = &insert[..last_char_index]; self.clear_selection(); @@ -225,7 +235,7 @@ impl<T: ClipboardProvider> TextInput<T> { let lines_suffix = &self.lines[end.line + 1..]; let mut insert_lines = if self.multiline { - chars_to_insert.split('\n').map(|s| DOMString::from(s.to_owned())).collect() + chars_to_insert.split('\n').map(|s| DOMString::from(s)).collect() } else { vec!(DOMString::from(chars_to_insert)) }; diff --git a/tests/unit/script/textinput.rs b/tests/unit/script/textinput.rs index 2613c0f640a..ee40c9ff50c 100644 --- a/tests/unit/script/textinput.rs +++ b/tests/unit/script/textinput.rs @@ -207,6 +207,15 @@ fn test_textinput_replace_selection() { } #[test] +fn test_textinput_replace_selection_multibyte_char() { + let mut textinput = text_input(Lines::Single, "é"); + textinput.adjust_horizontal_by_one(Direction::Forward, Selection::Selected); + + textinput.replace_selection(DOMString::from("e")); + assert_eq!(textinput.get_content(), "e"); +} + +#[test] fn test_textinput_current_line_length() { let mut textinput = text_input(Lines::Multiple, "abc\nde\nf"); assert_eq!(textinput.current_line_length(), 3); |