display input caret for textarea. fixes #7758

This commit is contained in:
Florian Merz 2015-10-21 22:38:23 +02:00
parent 50ec235384
commit 80e8a674e2
6 changed files with 67 additions and 21 deletions

View file

@ -431,9 +431,19 @@ fn split_first_fragment_at_newline_if_necessary(fragments: &mut LinkedList<Fragm
string_before =
unscanned_text_fragment_info.text[..(position + 1)].to_owned();
insertion_point_before = unscanned_text_fragment_info.insertion_point;
unscanned_text_fragment_info.text =
unscanned_text_fragment_info.text[(position + 1)..].to_owned().into_boxed_str();
let offset = CharIndex(string_before.char_indices().count() as isize);
match unscanned_text_fragment_info.insertion_point {
Some(insertion_point) if insertion_point >= 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(

View file

@ -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::<HTMLTextAreaElement>() {
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::<HTMLInputElement>() {
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

View file

@ -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<HTMLTextAreaElement> {
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 {

View file

@ -455,4 +455,14 @@ impl<T: ClipboardProvider> TextInput<T> {
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
}
}

View file

@ -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
}

View file

@ -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);
};
}