mirror of
https://github.com/servo/servo.git
synced 2025-06-25 01:24:37 +01:00
Use byte indices instead of char indices for text runs
Replace character indices with UTF-8 byte offsets throughout the code dealing with text shaping and breaking. This eliminates a lot of complexity when converting from one to the other, and interoperates better with the rest of the Rust ecosystem.
This commit is contained in:
parent
dba878dfb2
commit
659305fe0a
15 changed files with 259 additions and 437 deletions
|
@ -43,10 +43,11 @@ use style::element_state::*;
|
|||
use textinput::KeyReaction::{DispatchInput, Nothing, RedrawSelection, TriggerDefaultAction};
|
||||
use textinput::Lines::Single;
|
||||
use textinput::{TextInput, SelectionDirection};
|
||||
use util::str::{DOMString, search_index};
|
||||
use util::str::{DOMString};
|
||||
|
||||
const DEFAULT_SUBMIT_VALUE: &'static str = "Submit";
|
||||
const DEFAULT_RESET_VALUE: &'static str = "Reset";
|
||||
const PASSWORD_REPLACEMENT_CHAR: char = '●';
|
||||
|
||||
#[derive(JSTraceable, PartialEq, Copy, Clone)]
|
||||
#[allow(dead_code)]
|
||||
|
@ -174,7 +175,7 @@ pub trait LayoutHTMLInputElementHelpers {
|
|||
#[allow(unsafe_code)]
|
||||
unsafe fn size_for_layout(self) -> u32;
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn selection_for_layout(self) -> Option<Range<isize>>;
|
||||
unsafe fn selection_for_layout(self) -> Option<Range<usize>>;
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn checked_state_for_layout(self) -> bool;
|
||||
#[allow(unsafe_code)]
|
||||
|
@ -207,8 +208,7 @@ impl LayoutHTMLInputElementHelpers for LayoutJS<HTMLInputElement> {
|
|||
InputType::InputPassword => {
|
||||
let text = get_raw_textinput_value(self);
|
||||
if !text.is_empty() {
|
||||
// The implementation of selection_for_layout expects a 1:1 mapping of chars.
|
||||
text.chars().map(|_| '●').collect()
|
||||
text.chars().map(|_| PASSWORD_REPLACEMENT_CHAR).collect()
|
||||
} else {
|
||||
String::from((*self.unsafe_get()).placeholder.borrow_for_layout().clone())
|
||||
}
|
||||
|
@ -216,7 +216,6 @@ impl LayoutHTMLInputElementHelpers for LayoutJS<HTMLInputElement> {
|
|||
_ => {
|
||||
let text = get_raw_textinput_value(self);
|
||||
if !text.is_empty() {
|
||||
// The implementation of selection_for_layout expects a 1:1 mapping of chars.
|
||||
String::from(text)
|
||||
} else {
|
||||
String::from((*self.unsafe_get()).placeholder.borrow_for_layout().clone())
|
||||
|
@ -233,24 +232,29 @@ impl LayoutHTMLInputElementHelpers for LayoutJS<HTMLInputElement> {
|
|||
|
||||
#[allow(unrooted_must_root)]
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn selection_for_layout(self) -> Option<Range<isize>> {
|
||||
unsafe fn selection_for_layout(self) -> Option<Range<usize>> {
|
||||
if !(*self.unsafe_get()).upcast::<Element>().focus_state() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Use the raw textinput to get the index as long as we use a 1:1 char mapping
|
||||
// in value_for_layout.
|
||||
let raw = match (*self.unsafe_get()).input_type.get() {
|
||||
InputType::InputText |
|
||||
InputType::InputPassword => get_raw_textinput_value(self),
|
||||
_ => return None
|
||||
};
|
||||
let textinput = (*self.unsafe_get()).textinput.borrow_for_layout();
|
||||
let selection = textinput.get_absolute_selection_range();
|
||||
let begin_byte = selection.begin();
|
||||
let begin = search_index(begin_byte, raw.char_indices());
|
||||
let length = search_index(selection.length(), raw[begin_byte..].char_indices());
|
||||
Some(Range::new(begin, length))
|
||||
|
||||
match (*self.unsafe_get()).input_type.get() {
|
||||
InputType::InputPassword => {
|
||||
let text = get_raw_textinput_value(self);
|
||||
let sel = textinput.get_absolute_selection_range();
|
||||
|
||||
// Translate indices from the raw value to indices in the replacement value.
|
||||
let char_start = text[.. sel.begin()].chars().count();
|
||||
let char_count = text[sel.begin() .. sel.end()].chars().count();
|
||||
|
||||
let bytes_per_char = PASSWORD_REPLACEMENT_CHAR.len_utf8();
|
||||
Some(Range::new(char_start * bytes_per_char,
|
||||
char_count * bytes_per_char))
|
||||
}
|
||||
InputType::InputText => Some(textinput.get_absolute_selection_range()),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unrooted_must_root)]
|
||||
|
|
|
@ -47,7 +47,7 @@ pub trait LayoutHTMLTextAreaElementHelpers {
|
|||
#[allow(unsafe_code)]
|
||||
unsafe fn get_value_for_layout(self) -> String;
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn get_absolute_selection_for_layout(self) -> Option<Range<usize>>;
|
||||
unsafe fn selection_for_layout(self) -> Option<Range<usize>>;
|
||||
#[allow(unsafe_code)]
|
||||
fn get_cols(self) -> u32;
|
||||
#[allow(unsafe_code)]
|
||||
|
@ -63,13 +63,12 @@ impl LayoutHTMLTextAreaElementHelpers for LayoutJS<HTMLTextAreaElement> {
|
|||
|
||||
#[allow(unrooted_must_root)]
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn get_absolute_selection_for_layout(self) -> Option<Range<usize>> {
|
||||
if (*self.unsafe_get()).upcast::<Element>().focus_state() {
|
||||
Some((*self.unsafe_get()).textinput.borrow_for_layout()
|
||||
.get_absolute_selection_range())
|
||||
} else {
|
||||
None
|
||||
unsafe fn selection_for_layout(self) -> Option<Range<usize>> {
|
||||
if !(*self.unsafe_get()).upcast::<Element>().focus_state() {
|
||||
return None;
|
||||
}
|
||||
let textinput = (*self.unsafe_get()).textinput.borrow_for_layout();
|
||||
Some(textinput.get_absolute_selection_range())
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue