diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 721d7ea1573..7285adca0e3 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -46,7 +46,7 @@ use url::Url; use util::geometry::{Au, ZERO_POINT}; use util::logical_geometry::{LogicalRect, LogicalSize, LogicalMargin, WritingMode}; use util::range::*; -use util::str::is_whitespace; +use util::str::{is_whitespace, slice_chars}; use util; /// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position @@ -204,8 +204,8 @@ impl fmt::Debug for SpecificFragmentInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { SpecificFragmentInfo::ScannedText(ref info) => { - write!(f, " \"{}\"", info.run.text.slice_chars(info.range.begin().get() as usize, - info.range.end().get() as usize)) + write!(f, " \"{}\"", slice_chars(&*info.run.text, info.range.begin().get() as usize, + info.range.end().get() as usize)) } _ => Ok(()) } @@ -2094,7 +2094,8 @@ impl Fragment { let mut leading_whitespace_character_count = 0; { - let text = scanned_text_fragment_info.run.text.slice_chars( + let text = slice_chars( + &*scanned_text_fragment_info.run.text, scanned_text_fragment_info.range.begin().to_usize(), scanned_text_fragment_info.range.end().to_usize()); for character in text.chars() { diff --git a/components/layout/inline.rs b/components/layout/inline.rs index bc5e432a82e..abf23e488dd 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -35,6 +35,7 @@ use unicode_bidi; use util::geometry::{Au, MAX_AU, ZERO_RECT}; use util::logical_geometry::{LogicalRect, LogicalSize, WritingMode}; use util::range::{Range, RangeIndex}; +use util::str::slice_chars; use util; // From gfxFontConstants.h in Firefox @@ -1801,7 +1802,7 @@ fn strip_trailing_whitespace_if_necessary(text_run: &TextRun, range: &mut Range< debug!("stripping trailing whitespace: range={:?}, len={}", range, text_run.text.chars().count()); - let text = text_run.text.slice_chars(range.begin().to_usize(), range.end().to_usize()); + let text = slice_chars(&*text_run.text, range.begin().to_usize(), range.end().to_usize()); let mut trailing_whitespace_character_count = 0; for ch in text.chars().rev() { if util::str::char_is_whitespace(ch) { diff --git a/components/layout/lib.rs b/components/layout/lib.rs index c12cb903d33..c68e5f300cd 100644 --- a/components/layout/lib.rs +++ b/components/layout/lib.rs @@ -13,7 +13,6 @@ #![feature(mpsc_select)] #![feature(plugin)] #![feature(raw)] -#![feature(slice_chars)] #![feature(step_by)] #![feature(str_char)] #![feature(unsafe_no_drop_flag)] diff --git a/components/script/dom/characterdata.rs b/components/script/dom/characterdata.rs index dead19c79b6..377a69b3d2d 100644 --- a/components/script/dom/characterdata.rs +++ b/components/script/dom/characterdata.rs @@ -17,7 +17,7 @@ use dom::element::Element; use dom::eventtarget::{EventTarget, EventTargetTypeId}; use dom::node::{Node, NodeHelpers, NodeTypeId}; -use util::str::DOMString; +use util::str::{DOMString, slice_chars}; use std::borrow::ToOwned; use std::cell::Ref; @@ -74,7 +74,7 @@ impl<'a> CharacterDataMethods for &'a CharacterData { } // Steps 3-4. let end = if length - offset < count { length } else { offset + count }; - Ok(data.slice_chars(offset as usize, end as usize).to_owned()) + Ok(slice_chars(&*data, offset as usize, end as usize).to_owned()) } // https://dom.spec.whatwg.org/#dom-characterdata-appenddatadata @@ -107,9 +107,9 @@ impl<'a> CharacterDataMethods for &'a CharacterData { }; // Step 4: Mutation observers. // Step 5. - let mut data = self.data.borrow().slice_chars(0, offset as usize).to_owned(); + let mut data = slice_chars(&*self.data.borrow(), 0, offset as usize).to_owned(); data.push_str(&arg); - data.push_str(&self.data.borrow().slice_chars((offset + count) as usize, length as usize)); + data.push_str(slice_chars(&*self.data.borrow(), (offset + count) as usize, length as usize)); *self.data.borrow_mut() = data; // FIXME: Once we have `Range`, we should implement step7 to step11 Ok(()) diff --git a/components/script/lib.rs b/components/script/lib.rs index 3e38d1c88fc..640aad8e6e1 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -21,7 +21,6 @@ #![feature(plugin)] #![feature(ref_slice)] #![feature(rc_unique)] -#![feature(slice_chars)] #![feature(str_utf16)] #![feature(unicode)] #![feature(vec_push_all)] diff --git a/components/script/textinput.rs b/components/script/textinput.rs index 9ce3a482a65..a88f2bf491a 100644 --- a/components/script/textinput.rs +++ b/components/script/textinput.rs @@ -8,7 +8,7 @@ use clipboard_provider::ClipboardProvider; use dom::keyboardevent::{KeyboardEvent, KeyboardEventHelpers, key_value}; use msg::constellation_msg::{SHIFT, CONTROL, ALT, SUPER}; use msg::constellation_msg::{Key, KeyModifiers}; -use util::str::DOMString; +use util::str::{DOMString, slice_chars}; use std::borrow::ToOwned; use std::cmp::{min, max}; @@ -159,16 +159,16 @@ impl TextInput { self.get_sorted_selection().map(|(begin, end)| { if begin.line != end.line { let mut s = String::new(); - s.push_str(self.lines[begin.line].slice_chars(begin.index, self.lines[begin.line].len())); + s.push_str(slice_chars(&self.lines[begin.line], begin.index, self.lines[begin.line].len())); for (_, line) in self.lines.iter().enumerate().filter(|&(i,_)| begin.line < i && i < end.line) { s.push_str("\n"); s.push_str(line); } s.push_str("\n"); - s.push_str(self.lines[end.line].slice_chars(0, end.index)); + s.push_str(slice_chars(&self.lines[end.line], 0, end.index)); s } else { - self.lines[begin.line].slice_chars(begin.index, end.index).to_owned() + slice_chars(&self.lines[begin.line], begin.index, end.index).to_owned() } }) } @@ -178,8 +178,8 @@ impl TextInput { self.clear_selection(); let new_lines = { - let prefix = self.lines[begin.line].slice_chars(0, begin.index); - let suffix = self.lines[end.line].slice_chars(end.index, self.lines[end.line].chars().count()); + let prefix = slice_chars(&self.lines[begin.line], 0, begin.index); + let suffix = slice_chars(&self.lines[end.line], end.index, self.lines[end.line].chars().count()); let lines_prefix = &self.lines[..begin.line]; let lines_suffix = &self.lines[end.line + 1..]; diff --git a/components/util/str.rs b/components/util/str.rs index fe6127e1106..af688a1103e 100644 --- a/components/util/str.rs +++ b/components/util/str.rs @@ -335,3 +335,27 @@ pub fn str_join>(strs: &[T], join: &str) -> String { acc }) } + +// Lifted from Rust's StrExt implementation, which is being removed. +pub fn slice_chars(s: &str, begin: usize, end: usize) -> &str { + assert!(begin <= end); + let mut count = 0; + let mut begin_byte = None; + let mut end_byte = None; + + // This could be even more efficient by not decoding, + // only finding the char boundaries + for (idx, _) in s.char_indices() { + if count == begin { begin_byte = Some(idx); } + if count == end { end_byte = Some(idx); break; } + count += 1; + } + if begin_byte.is_none() && count == begin { begin_byte = Some(s.len()) } + if end_byte.is_none() && count == end { end_byte = Some(s.len()) } + + match (begin_byte, end_byte) { + (None, _) => panic!("slice_chars: `begin` is beyond end of string"), + (_, None) => panic!("slice_chars: `end` is beyond end of string"), + (Some(a), Some(b)) => unsafe { s.slice_unchecked(a, b) } + } +}