From 80e8a674e219a6b65e070675d1775f0bd0e2ad93 Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Wed, 21 Oct 2015 22:38:23 +0200 Subject: [PATCH] display input caret for textarea. fixes #7758 --- components/layout/text.rs | 12 +++++++- components/layout/wrapper.rs | 29 ++++++++------------ components/script/dom/htmltextareaelement.rs | 8 ++++++ components/script/textinput.rs | 10 +++++++ components/util/str.rs | 15 +++++++++- tests/unit/util/str.rs | 14 +++++++++- 6 files changed, 67 insertions(+), 21 deletions(-) diff --git a/components/layout/text.rs b/components/layout/text.rs index e007eb3d25b..feab75efa65 100644 --- a/components/layout/text.rs +++ b/components/layout/text.rs @@ -431,9 +431,19 @@ fn split_first_fragment_at_newline_if_necessary(fragments: &mut LinkedList= offset => { + insertion_point_before = None; + unscanned_text_fragment_info.insertion_point = Some(insertion_point - offset); + } + Some(_) | None => { + insertion_point_before = unscanned_text_fragment_info.insertion_point; + unscanned_text_fragment_info.insertion_point = None; + } + }; } first_fragment.transform(first_fragment.border_box.size, SpecificFragmentInfo::UnscannedText( diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 2be8382ee4c..e2c0bd89f19 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -71,7 +71,7 @@ use style::node::TElementAttributes; use style::properties::ComputedValues; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock}; use url::Url; -use util::str::is_whitespace; +use util::str::{is_whitespace, search_index}; /// A wrapper so that layout can access only the methods that it should have access to. Layout must /// only ever see these and must never see instances of `LayoutJS`. @@ -918,24 +918,17 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { let this = unsafe { self.get_jsmanaged() }; - let input = this.downcast(); - if let Some(input) = input { - let insertion_point = unsafe { - input.get_insertion_point_for_layout() - }; - if let Some(insertion_point) = insertion_point { - let text = unsafe { - input.get_value_for_layout() - }; - let mut character_count = 0; - for (character_index, _) in text.char_indices() { - if character_index == insertion_point.index { - return Some(CharIndex(character_count)) - } - character_count += 1 - } - return Some(CharIndex(character_count)) + if let Some(area) = this.downcast::() { + let insertion_point = unsafe { area.get_absolute_insertion_point_for_layout() }; + let text = unsafe { area.get_value_for_layout() }; + return Some(CharIndex(search_index(insertion_point, text.char_indices()))); + } + if let Some(input) = this.downcast::() { + let insertion_point = unsafe { input.get_insertion_point_for_layout() }; + if let Some(insertion_point) = insertion_point { + let text = unsafe { input.get_value_for_layout() }; + return Some(CharIndex(search_index(insertion_point.index, text.char_indices()))); } } None diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index d802760a308..2ef5a24775d 100644 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -46,6 +46,8 @@ pub struct HTMLTextAreaElement { pub trait LayoutHTMLTextAreaElementHelpers { #[allow(unsafe_code)] unsafe fn get_value_for_layout(self) -> String; + #[allow(unsafe_code)] + unsafe fn get_absolute_insertion_point_for_layout(self) -> usize; } pub trait RawLayoutHTMLTextAreaElementHelpers { @@ -61,6 +63,12 @@ impl LayoutHTMLTextAreaElementHelpers for LayoutJS { unsafe fn get_value_for_layout(self) -> String { (*self.unsafe_get()).textinput.borrow_for_layout().get_content() } + + #[allow(unrooted_must_root)] + #[allow(unsafe_code)] + unsafe fn get_absolute_insertion_point_for_layout(self) -> usize { + (*self.unsafe_get()).textinput.borrow_for_layout().get_absolute_insertion_point() + } } impl<'a> RawLayoutHTMLTextAreaElementHelpers for &'a HTMLTextAreaElement { diff --git a/components/script/textinput.rs b/components/script/textinput.rs index 627ecf29a5f..c75d246d3ba 100644 --- a/components/script/textinput.rs +++ b/components/script/textinput.rs @@ -455,4 +455,14 @@ impl TextInput { self.edit_point.line = min(self.edit_point.line, self.lines.len() - 1); self.edit_point.index = min(self.edit_point.index, self.current_line_length()); } + + pub fn get_absolute_insertion_point(&self) -> usize { + self.lines.iter().enumerate().fold(0, |acc, (i, val)| { + if i < self.edit_point.line { + acc + val.len() + 1 // +1 for the \n + } else { + acc + } + }) + self.edit_point.index + } } diff --git a/components/util/str.rs b/components/util/str.rs index 78bc8824707..91d5562f4e4 100644 --- a/components/util/str.rs +++ b/components/util/str.rs @@ -11,7 +11,7 @@ use std::borrow::ToOwned; use std::ffi::CStr; use std::iter::{Filter, Peekable}; use std::ops::Deref; -use std::str::{FromStr, Split, from_utf8}; +use std::str::{CharIndices, FromStr, Split, from_utf8}; pub type DOMString = String; pub type StaticCharVec = &'static [char]; @@ -420,3 +420,16 @@ pub fn slice_chars(s: &str, begin: usize, end: usize) -> &str { (Some(a), Some(b)) => unsafe { s.slice_unchecked(a, b) } } } + +// searches a character index in CharIndices +// returns indices.count if not found +pub fn search_index(index: usize, indices: CharIndices) -> isize { + let mut character_count = 0; + for (character_index, _) in indices { + if character_index == index { + return character_count; + } + character_count += 1 + } + character_count +} diff --git a/tests/unit/util/str.rs b/tests/unit/util/str.rs index c03d8c8086c..fd3a4973d66 100644 --- a/tests/unit/util/str.rs +++ b/tests/unit/util/str.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use util::str::{split_html_space_chars, str_join}; +use util::str::{search_index, split_html_space_chars, str_join}; #[test] @@ -34,3 +34,15 @@ pub fn test_str_join_many() { let expected = "-alpha--beta-gamma-"; assert_eq!(actual, expected); } + +#[test] +pub fn test_search_index() { + let tuples = [("", 1, 0), + ("foo", 8, 3), + ("føo", 8, 3), + ("foo", 2, 2), + ("føo", 2, 3)]; + for t in tuples.iter() { + assert_eq!(search_index(t.1, t.0.char_indices()), t.2); + }; +}