mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
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:
parent
f2f05869d6
commit
6171000875
17 changed files with 229 additions and 62 deletions
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue