Highlight selected text in input fields

Fixes #9993.  This does not yet allow stylesheets to set the selection colors;
instead it uses a hard-coded orange background and white foreground.
This commit is contained in:
Matt Brubeck 2016-03-18 16:38:17 -07:00
parent f2f05869d6
commit 6171000875
17 changed files with 229 additions and 62 deletions

View file

@ -172,17 +172,21 @@ impl TextRunScanner {
for (fragment_index, in_fragment) in self.clump.iter().enumerate() {
let mut mapping = RunMapping::new(&run_info_list[..], &run_info, fragment_index);
let text;
let insertion_point;
let selection;
match in_fragment.specific {
SpecificFragmentInfo::UnscannedText(ref text_fragment_info) => {
text = &text_fragment_info.text;
insertion_point = text_fragment_info.insertion_point;
selection = text_fragment_info.selection;
}
_ => panic!("Expected an unscanned text fragment!"),
};
let insertion_point = match selection {
Some(range) if range.is_empty() => Some(range.begin()),
_ => None
};
let (mut start_position, mut end_position) = (0, 0);
for character in text.chars() {
for (char_index, character) in text.chars().enumerate() {
// Search for the first font in this font group that contains a glyph for this
// character.
let mut font_index = 0;
@ -213,11 +217,18 @@ impl TextRunScanner {
run_info.script = script;
}
let selected = match selection {
Some(range) => range.contains(CharIndex(char_index as isize)),
None => false
};
// Now, if necessary, flush the mapping we were building up.
if run_info.font_index != font_index ||
run_info.bidi_level != bidi_level ||
!compatible_script
{
let flush_run = run_info.font_index != font_index ||
run_info.bidi_level != bidi_level ||
!compatible_script;
let flush_mapping = flush_run || mapping.selected != selected;
if flush_mapping {
if end_position > start_position {
mapping.flush(&mut mappings,
&mut run_info,
@ -230,8 +241,10 @@ impl TextRunScanner {
end_position);
}
if run_info.text.len() > 0 {
run_info_list.push(run_info);
run_info = RunInfo::new();
if flush_run {
run_info_list.push(run_info);
run_info = RunInfo::new();
}
mapping = RunMapping::new(&run_info_list[..],
&run_info,
fragment_index);
@ -239,6 +252,7 @@ impl TextRunScanner {
run_info.font_index = font_index;
run_info.bidi_level = bidi_level;
run_info.script = script;
mapping.selected = selected;
}
// Consume this character.
@ -334,7 +348,8 @@ impl TextRunScanner {
scanned_run.run,
mapping.char_range,
text_size,
&scanned_run.insertion_point,
scanned_run.insertion_point,
mapping.selected,
requires_line_break_afterward_if_wrapping_on_newlines);
let new_metrics = new_text_fragment_info.run.metrics_for_range(&mapping.char_range);
@ -408,7 +423,7 @@ fn split_first_fragment_at_newline_if_necessary(fragments: &mut LinkedList<Fragm
let new_fragment = {
let mut first_fragment = fragments.front_mut().unwrap();
let string_before;
let insertion_point_before;
let selection_before;
{
if !first_fragment.white_space().preserve_newlines() {
return;
@ -433,21 +448,28 @@ fn split_first_fragment_at_newline_if_necessary(fragments: &mut LinkedList<Fragm
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);
match unscanned_text_fragment_info.selection {
Some(ref mut selection) if selection.begin() >= offset => {
// Selection is entirely in the second fragment.
selection_before = None;
selection.shift_by(-offset);
}
Some(_) | None => {
insertion_point_before = unscanned_text_fragment_info.insertion_point;
unscanned_text_fragment_info.insertion_point = None;
Some(ref mut selection) if selection.end() > offset => {
// Selection is split across two fragments.
selection_before = Some(Range::new(selection.begin(), offset));
*selection = Range::new(CharIndex(0), selection.end() - offset);
}
_ => {
// Selection is entirely in the first fragment.
selection_before = unscanned_text_fragment_info.selection;
unscanned_text_fragment_info.selection = None;
}
};
}
first_fragment.transform(first_fragment.border_box.size,
SpecificFragmentInfo::UnscannedText(
UnscannedTextFragmentInfo::new(string_before,
insertion_point_before)))
selection_before)))
};
fragments.push_front(new_fragment);
@ -494,6 +516,8 @@ struct RunMapping {
old_fragment_index: usize,
/// The index of the text run we're going to create.
text_run_index: usize,
/// Is the text in this fragment selected?
selected: bool,
}
impl RunMapping {
@ -508,6 +532,7 @@ impl RunMapping {
byte_range: Range::new(0, 0),
old_fragment_index: fragment_index,
text_run_index: run_info_list.len(),
selected: false,
}
}