aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2016-04-28 20:22:09 -0700
committerbors-servo <lbergstrom+bors@mozilla.com>2016-04-28 20:22:09 -0700
commitcf121ad8dff90b8fa55558ca9bdcbfe29512a617 (patch)
tree8f8ff7f5e68b18eb228acbc1448a7c4f451e1e69 /components/layout
parent1177ef5869e02b5129ebde6fa9780c93d362e16c (diff)
parentc4872d95445636ef4dec45cbfc5c2d643c4b9441 (diff)
downloadservo-cf121ad8dff90b8fa55558ca9bdcbfe29512a617.tar.gz
servo-cf121ad8dff90b8fa55558ca9bdcbfe29512a617.zip
Auto merge of #10895 - mbrubeck:byteindex, r=pcwalton
Use byte indices instead of char indices for text runs Replace character indices with UTF-8 byte offsets throughout all code dealing with text runs. This eliminates a lot of complexity when converting from one to the other, and interoperates better with the rest of the Rust ecosystem. For most code this is just a simple replacement of char indices with byte indices. In a few places like glyph storage and text fragment scanning, it also lets us get rid of code that existed only to map between bytes and chars. Also includes some related fixes to text shaping, discovered while working on this conversion. See the commit messages for details. r? @pcwalton <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/10895) <!-- Reviewable:end -->
Diffstat (limited to 'components/layout')
-rw-r--r--components/layout/display_list_builder.rs4
-rw-r--r--components/layout/fragment.rs112
-rw-r--r--components/layout/text.rs81
-rw-r--r--components/layout/webrender_helpers.rs2
-rw-r--r--components/layout/wrapper.rs37
5 files changed, 88 insertions, 148 deletions
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index de76e2b20cc..495c22e7589 100644
--- a/components/layout/display_list_builder.rs
+++ b/components/layout/display_list_builder.rs
@@ -31,7 +31,7 @@ use gfx::display_list::{LineDisplayItem, OpaqueNode, SolidColorDisplayItem};
use gfx::display_list::{StackingContext, StackingContextId, StackingContextType};
use gfx::display_list::{TextDisplayItem, TextOrientation, WebRenderImageInfo};
use gfx::paint_thread::THREAD_TINT_COLORS;
-use gfx::text::glyph::CharIndex;
+use gfx::text::glyph::ByteIndex;
use gfx_traits::{color, ScrollPolicy};
use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT};
use ipc_channel::ipc::{self};
@@ -965,7 +965,7 @@ impl FragmentDisplayListBuilding for Fragment {
Some(insertion_point_index) => insertion_point_index,
None => return,
};
- let range = Range::new(CharIndex(0), insertion_point_index);
+ let range = Range::new(ByteIndex(0), insertion_point_index);
let advance = scanned_text_fragment_info.run.advance_for_range(&range);
let insertion_point_bounds;
diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs
index 5612a322b95..ce9e55496c7 100644
--- a/components/layout/fragment.rs
+++ b/components/layout/fragment.rs
@@ -15,7 +15,7 @@ use flow::{self, Flow};
use flow_ref::{self, FlowRef};
use gfx;
use gfx::display_list::{BLUR_INFLATION_FACTOR, FragmentType, OpaqueNode, StackingContextId};
-use gfx::text::glyph::CharIndex;
+use gfx::text::glyph::ByteIndex;
use gfx::text::text_run::{TextRun, TextRunSlice};
use gfx_traits::{LayerId, LayerType};
use incremental::{RECONSTRUCT_FLOW, RestyleDamage};
@@ -48,7 +48,6 @@ use text;
use text::TextRunScanner;
use url::Url;
use util;
-use util::str::slice_chars;
use wrapper::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
/// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position
@@ -227,13 +226,8 @@ impl SpecificFragmentInfo {
impl fmt::Debug for SpecificFragmentInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- SpecificFragmentInfo::ScannedText(ref info) => {
- write!(f, "{:?}", slice_chars(&*info.run.text, info.range.begin().get() as usize,
- info.range.end().get() as usize))
- }
- SpecificFragmentInfo::UnscannedText(ref info) => {
- write!(f, "{:?}", info.text)
- }
+ SpecificFragmentInfo::ScannedText(ref info) => write!(f, "{:?}", info.text()),
+ SpecificFragmentInfo::UnscannedText(ref info) => write!(f, "{:?}", info.text),
_ => Ok(())
}
}
@@ -657,16 +651,16 @@ pub struct ScannedTextFragmentInfo {
/// The intrinsic size of the text fragment.
pub content_size: LogicalSize<Au>,
- /// The position of the insertion point in characters, if any.
- pub insertion_point: Option<CharIndex>,
+ /// The byte offset of the insertion point, if any.
+ pub insertion_point: Option<ByteIndex>,
/// The range within the above text run that this represents.
- pub range: Range<CharIndex>,
+ pub range: Range<ByteIndex>,
/// The endpoint of the above range, including whitespace that was stripped out. This exists
/// so that we can restore the range to its original value (before line breaking occurred) when
/// performing incremental reflow.
- pub range_end_including_stripped_whitespace: CharIndex,
+ pub range_end_including_stripped_whitespace: ByteIndex,
pub flags: ScannedTextFlags,
}
@@ -685,9 +679,9 @@ bitflags! {
impl ScannedTextFragmentInfo {
/// Creates the information specific to a scanned text fragment from a range and a text run.
pub fn new(run: Arc<TextRun>,
- range: Range<CharIndex>,
+ range: Range<ByteIndex>,
content_size: LogicalSize<Au>,
- insertion_point: Option<CharIndex>,
+ insertion_point: Option<ByteIndex>,
flags: ScannedTextFlags)
-> ScannedTextFragmentInfo {
ScannedTextFragmentInfo {
@@ -700,6 +694,10 @@ impl ScannedTextFragmentInfo {
}
}
+ pub fn text(&self) -> &str {
+ &self.run.text[self.range.begin().to_usize() .. self.range.end().to_usize()]
+ }
+
pub fn requires_line_break_afterward_if_wrapping_on_newlines(&self) -> bool {
self.flags.contains(REQUIRES_LINE_BREAK_AFTERWARD_IF_WRAPPING_ON_NEWLINES)
}
@@ -715,12 +713,12 @@ impl ScannedTextFragmentInfo {
pub struct SplitInfo {
// TODO(bjz): this should only need to be a single character index, but both values are
// currently needed for splitting in the `inline::try_append_*` functions.
- pub range: Range<CharIndex>,
+ pub range: Range<ByteIndex>,
pub inline_size: Au,
}
impl SplitInfo {
- fn new(range: Range<CharIndex>, info: &ScannedTextFragmentInfo) -> SplitInfo {
+ fn new(range: Range<ByteIndex>, info: &ScannedTextFragmentInfo) -> SplitInfo {
let inline_size = info.run.advance_for_range(&range);
SplitInfo {
range: range,
@@ -755,13 +753,13 @@ pub struct UnscannedTextFragmentInfo {
pub text: Box<str>,
/// The selected text range. An empty range represents the insertion point.
- pub selection: Option<Range<CharIndex>>,
+ pub selection: Option<Range<ByteIndex>>,
}
impl UnscannedTextFragmentInfo {
/// Creates a new instance of `UnscannedTextFragmentInfo` from the given text.
#[inline]
- pub fn new(text: String, selection: Option<Range<CharIndex>>) -> UnscannedTextFragmentInfo {
+ pub fn new(text: String, selection: Option<Range<ByteIndex>>) -> UnscannedTextFragmentInfo {
UnscannedTextFragmentInfo {
text: text.into_boxed_str(),
selection: selection,
@@ -1611,7 +1609,7 @@ impl Fragment {
};
let mut remaining_inline_size = max_inline_size;
- let mut inline_start_range = Range::new(text_fragment_info.range.begin(), CharIndex(0));
+ let mut inline_start_range = Range::new(text_fragment_info.range.begin(), ByteIndex(0));
let mut inline_end_range = None;
let mut overflowing = false;
@@ -1651,7 +1649,7 @@ impl Fragment {
// We're going to overflow the line.
overflowing = true;
inline_start_range = slice.text_run_range();
- remaining_range = Range::new(slice.text_run_range().end(), CharIndex(0));
+ remaining_range = Range::new(slice.text_run_range().end(), ByteIndex(0));
remaining_range.extend_to(text_fragment_info.range.end());
}
@@ -2322,32 +2320,20 @@ impl Fragment {
match self.specific {
SpecificFragmentInfo::ScannedText(ref mut scanned_text_fragment_info) => {
- let mut leading_whitespace_character_count = 0;
- {
- 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() {
- if util::str::char_is_whitespace(character) {
- leading_whitespace_character_count += 1
- } else {
- break
- }
- }
- }
+ let leading_whitespace_byte_count = scanned_text_fragment_info.text()
+ .find(|c| !util::str::char_is_whitespace(c))
+ .unwrap_or(scanned_text_fragment_info.text().len());
+ let whitespace_len = ByteIndex(leading_whitespace_byte_count as isize);
let whitespace_range = Range::new(scanned_text_fragment_info.range.begin(),
- CharIndex(leading_whitespace_character_count));
+ whitespace_len);
let text_bounds =
scanned_text_fragment_info.run.metrics_for_range(&whitespace_range).bounding_box;
self.border_box.size.inline = self.border_box.size.inline - text_bounds.size.width;
scanned_text_fragment_info.content_size.inline =
scanned_text_fragment_info.content_size.inline - text_bounds.size.width;
- scanned_text_fragment_info.range.adjust_by(
- CharIndex(leading_whitespace_character_count),
- -CharIndex(leading_whitespace_character_count));
+ scanned_text_fragment_info.range.adjust_by(whitespace_len, -whitespace_len);
WhitespaceStrippingResult::RetainFragment
}
@@ -2388,43 +2374,29 @@ impl Fragment {
match self.specific {
SpecificFragmentInfo::ScannedText(ref mut scanned_text_fragment_info) => {
- // FIXME(pcwalton): Is there a more clever (i.e. faster) way to do this?
- debug!("stripping trailing whitespace: range={:?}, len={}",
- scanned_text_fragment_info.range,
- scanned_text_fragment_info.run.text.chars().count());
- let mut trailing_whitespace_character_count = 0;
- let text_bounds;
- {
- 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 ch in text.chars().rev() {
- if util::str::char_is_whitespace(ch) {
- trailing_whitespace_character_count += 1
- } else {
- break
- }
+ let mut trailing_whitespace_start_byte = 0;
+ for (i, c) in scanned_text_fragment_info.text().char_indices().rev() {
+ if !util::str::char_is_whitespace(c) {
+ trailing_whitespace_start_byte = i + c.len_utf8();
+ break;
}
-
- let whitespace_range =
- Range::new(scanned_text_fragment_info.range.end() -
- CharIndex(trailing_whitespace_character_count),
- CharIndex(trailing_whitespace_character_count));
- text_bounds = scanned_text_fragment_info.run
- .metrics_for_range(&whitespace_range)
- .bounding_box;
- self.border_box.size.inline = self.border_box.size.inline -
- text_bounds.size.width;
}
+ let whitespace_start = ByteIndex(trailing_whitespace_start_byte as isize);
+ let whitespace_len = scanned_text_fragment_info.range.length() - whitespace_start;
+ let whitespace_range = Range::new(whitespace_start, whitespace_len);
+
+ // FIXME: This may be unnecessary because these metrics will be recomputed in
+ // LineBreaker::strip_trailing_whitespace_from_pending_line_if_necessary
+ let text_bounds = scanned_text_fragment_info.run
+ .metrics_for_range(&whitespace_range)
+ .bounding_box;
+ self.border_box.size.inline = self.border_box.size.inline -
+ text_bounds.size.width;
scanned_text_fragment_info.content_size.inline =
scanned_text_fragment_info.content_size.inline - text_bounds.size.width;
- if trailing_whitespace_character_count != 0 {
- scanned_text_fragment_info.range.extend_by(
- CharIndex(-trailing_whitespace_character_count));
- }
-
+ scanned_text_fragment_info.range.extend_by(-whitespace_len);
WhitespaceStrippingResult::RetainFragment
}
SpecificFragmentInfo::UnscannedText(ref mut unscanned_text_fragment_info) => {
diff --git a/components/layout/text.rs b/components/layout/text.rs
index 22fbeb9ad1a..b7729608ce7 100644
--- a/components/layout/text.rs
+++ b/components/layout/text.rs
@@ -12,7 +12,7 @@ use fragment::{ScannedTextFragmentInfo, SELECTED, SpecificFragmentInfo, Unscanne
use gfx::font::{DISABLE_KERNING_SHAPING_FLAG, FontMetrics, IGNORE_LIGATURES_SHAPING_FLAG};
use gfx::font::{RTL_FLAG, RunMetrics, ShapingFlags, ShapingOptions};
use gfx::font_context::FontContext;
-use gfx::text::glyph::CharIndex;
+use gfx::text::glyph::ByteIndex;
use gfx::text::text_run::TextRun;
use gfx::text::util::{self, CompressionMode};
use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFragments, LAST_FRAGMENT_OF_ELEMENT};
@@ -174,7 +174,7 @@ impl TextRunScanner {
for (fragment_index, in_fragment) in self.clump.iter().enumerate() {
debug!(" flushing {:?}", in_fragment);
- let mut mapping = RunMapping::new(&run_info_list[..], &run_info, fragment_index);
+ let mut mapping = RunMapping::new(&run_info_list[..], fragment_index);
let text;
let selection;
match in_fragment.specific {
@@ -188,13 +188,13 @@ impl TextRunScanner {
Some(range) if range.is_empty() => {
// `range` is the range within the current fragment. To get the range
// within the text run, offset it by the length of the preceding fragments.
- Some(range.begin() + CharIndex(run_info.character_length as isize))
+ Some(range.begin() + ByteIndex(run_info.text.len() as isize))
}
_ => None
};
let (mut start_position, mut end_position) = (0, 0);
- for (char_index, character) in text.chars().enumerate() {
+ for (byte_index, character) in text.char_indices() {
// Search for the first font in this font group that contains a glyph for this
// character.
let mut font_index = 0;
@@ -226,7 +226,7 @@ impl TextRunScanner {
}
let selected = match selection {
- Some(range) => range.contains(CharIndex(char_index as isize)),
+ Some(range) => range.contains(ByteIndex(byte_index as isize)),
None => false
};
@@ -251,7 +251,6 @@ impl TextRunScanner {
run_info = RunInfo::new();
}
mapping = RunMapping::new(&run_info_list[..],
- &run_info,
fragment_index);
}
run_info.font_index = font_index;
@@ -343,11 +342,14 @@ impl TextRunScanner {
let mut mapping = mappings.next().unwrap();
let scanned_run = runs[mapping.text_run_index].clone();
+ let mut byte_range = Range::new(ByteIndex(mapping.byte_range.begin() as isize),
+ ByteIndex(mapping.byte_range.length() as isize));
+
let requires_line_break_afterward_if_wrapping_on_newlines =
!mapping.byte_range.is_empty() &&
scanned_run.run.text.char_at_reverse(mapping.byte_range.end()) == '\n';
if requires_line_break_afterward_if_wrapping_on_newlines {
- mapping.char_range.extend_by(CharIndex(-1));
+ byte_range.extend_by(ByteIndex(-1)); // Trim the '\n'
}
let text_size = old_fragment.border_box.size;
@@ -368,12 +370,12 @@ impl TextRunScanner {
let mut new_text_fragment_info = box ScannedTextFragmentInfo::new(
scanned_run.run,
- mapping.char_range,
+ byte_range,
text_size,
insertion_point,
flags);
- let new_metrics = new_text_fragment_info.run.metrics_for_range(&mapping.char_range);
+ let new_metrics = new_text_fragment_info.run.metrics_for_range(&byte_range);
let writing_mode = old_fragment.style.writing_mode;
let bounding_box_size = bounding_box_for_run_metrics(&new_metrics, writing_mode);
new_text_fragment_info.content_size = bounding_box_size;
@@ -490,7 +492,7 @@ fn split_first_fragment_at_newline_if_necessary(fragments: &mut LinkedList<Fragm
unscanned_text_fragment_info.text[..(position + 1)].to_owned();
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);
+ let offset = ByteIndex(string_before.len() as isize);
match unscanned_text_fragment_info.selection {
Some(ref mut selection) if selection.begin() >= offset => {
// Selection is entirely in the second fragment.
@@ -500,7 +502,7 @@ fn split_first_fragment_at_newline_if_necessary(fragments: &mut LinkedList<Fragm
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 = Range::new(ByteIndex(0), selection.end() - offset);
}
_ => {
// Selection is entirely in the first fragment.
@@ -523,11 +525,9 @@ struct RunInfo {
/// The text that will go in this text run.
text: String,
/// The insertion point in this text run, if applicable.
- insertion_point: Option<CharIndex>,
+ insertion_point: Option<ByteIndex>,
/// The index of the applicable font in the font group.
font_index: usize,
- /// A cached copy of the number of Unicode characters in the text run.
- character_length: usize,
/// The bidirection embedding level of this text run.
bidi_level: u8,
/// The Unicode script property of this text run.
@@ -540,7 +540,6 @@ impl RunInfo {
text: String::new(),
insertion_point: None,
font_index: 0,
- character_length: 0,
bidi_level: 0,
script: Script::Common,
}
@@ -552,9 +551,9 @@ impl RunInfo {
/// of this text run.
fn flush(mut self,
list: &mut Vec<RunInfo>,
- insertion_point: &mut Option<CharIndex>) {
+ insertion_point: &mut Option<ByteIndex>) {
if let Some(idx) = *insertion_point {
- let char_len = CharIndex(self.character_length as isize);
+ let char_len = ByteIndex(self.text.len() as isize);
if idx <= char_len {
// The insertion point is in this text run.
self.insertion_point = insertion_point.take()
@@ -571,8 +570,6 @@ impl RunInfo {
/// for it.
#[derive(Copy, Clone, Debug)]
struct RunMapping {
- /// The range of characters within the text fragment.
- char_range: Range<CharIndex>,
/// The range of byte indices within the text fragment.
byte_range: Range<usize>,
/// The index of the unscanned text fragment that this mapping corresponds to.
@@ -585,13 +582,10 @@ struct RunMapping {
impl RunMapping {
/// Given the current set of text runs, creates a run mapping for the next fragment.
- /// `run_info_list` describes the set of runs we've seen already, and `current_run_info`
- /// describes the run we just finished processing.
- fn new(run_info_list: &[RunInfo], current_run_info: &RunInfo, fragment_index: usize)
+ /// `run_info_list` describes the set of runs we've seen already.
+ fn new(run_info_list: &[RunInfo], fragment_index: usize)
-> RunMapping {
RunMapping {
- char_range: Range::new(CharIndex(current_run_info.character_length as isize),
- CharIndex(0)),
byte_range: Range::new(0, 0),
old_fragment_index: fragment_index,
text_run_index: run_info_list.len(),
@@ -620,26 +614,21 @@ impl RunMapping {
// Account for `text-transform`. (Confusingly, this is not handled in "text
// transformation" above, but we follow Gecko in the naming.)
let is_first_run = *start_position == 0;
- let character_count = apply_style_transform_if_necessary(&mut run_info.text,
- old_byte_length,
- text_transform,
- *last_whitespace,
- is_first_run);
-
- run_info.character_length = run_info.character_length + character_count;
+ apply_style_transform_if_necessary(&mut run_info.text, old_byte_length, text_transform,
+ *last_whitespace, is_first_run);
*start_position = end_position;
+ let new_byte_length = run_info.text.len();
+ let is_empty = new_byte_length == old_byte_length;
+
// Don't save mappings that contain only discarded characters.
// (But keep ones that contained no characters to begin with, since they might have been
// generated by an empty flow to draw its borders/padding/insertion point.)
- let is_empty = character_count == 0;
if is_empty && !was_empty {
return;
}
- let new_byte_length = run_info.text.len();
self.byte_range = Range::new(old_byte_length, new_byte_length - old_byte_length);
- self.char_range.extend_by(CharIndex(character_count as isize));
mappings.push(self)
}
@@ -648,10 +637,10 @@ impl RunMapping {
/// NOTE: We treat the range as inclusive at both ends, since the insertion point can lie
/// before the first character *or* after the last character, and should be drawn even if the
/// text is empty.
- fn contains_insertion_point(&self, insertion_point: Option<CharIndex>) -> bool {
- match insertion_point {
+ fn contains_insertion_point(&self, insertion_point: Option<ByteIndex>) -> bool {
+ match insertion_point.map(ByteIndex::to_usize) {
None => false,
- Some(idx) => self.char_range.begin() <= idx && idx <= self.char_range.end()
+ Some(idx) => self.byte_range.begin() <= idx && idx <= self.byte_range.end()
}
}
}
@@ -666,39 +655,29 @@ fn apply_style_transform_if_necessary(string: &mut String,
first_character_position: usize,
text_transform: text_transform::T,
last_whitespace: bool,
- is_first_run: bool)
- -> usize {
+ is_first_run: bool) {
match text_transform {
- text_transform::T::none => string[first_character_position..].chars().count(),
+ text_transform::T::none => {}
text_transform::T::uppercase => {
let original = string[first_character_position..].to_owned();
string.truncate(first_character_position);
- let mut count = 0;
for ch in original.chars().flat_map(|ch| ch.to_uppercase()) {
string.push(ch);
- count += 1;
}
- count
}
text_transform::T::lowercase => {
let original = string[first_character_position..].to_owned();
string.truncate(first_character_position);
- let mut count = 0;
for ch in original.chars().flat_map(|ch| ch.to_lowercase()) {
string.push(ch);
- count += 1;
}
- count
}
text_transform::T::capitalize => {
let original = string[first_character_position..].to_owned();
string.truncate(first_character_position);
let mut capitalize_next_letter = is_first_run || last_whitespace;
- let mut count = 0;
for character in original.chars() {
- count += 1;
-
// FIXME(#4311, pcwalton): Should be the CSS/Unicode notion of a *typographic
// letter unit*, not an *alphabetic* character:
//
@@ -716,8 +695,6 @@ fn apply_style_transform_if_necessary(string: &mut String,
capitalize_next_letter = true
}
}
-
- count
}
}
}
@@ -725,7 +702,7 @@ fn apply_style_transform_if_necessary(string: &mut String,
#[derive(Clone)]
struct ScannedTextRun {
run: Arc<TextRun>,
- insertion_point: Option<CharIndex>,
+ insertion_point: Option<ByteIndex>,
}
/// Can a character with script `b` continue a text run with script `a`?
diff --git a/components/layout/webrender_helpers.rs b/components/layout/webrender_helpers.rs
index c3b28f8ecc1..053ecf87f50 100644
--- a/components/layout/webrender_helpers.rs
+++ b/components/layout/webrender_helpers.rs
@@ -392,7 +392,7 @@ impl WebRenderDisplayItemConverter for DisplayItem {
let mut glyphs = vec!();
for slice in item.text_run.natural_word_slices_in_visual_order(&item.range) {
- for glyph in slice.glyphs.iter_glyphs_for_char_range(&slice.range) {
+ for glyph in slice.glyphs.iter_glyphs_for_byte_range(&slice.range) {
let glyph_advance = glyph.advance();
let glyph_offset = glyph.offset().unwrap_or(Point2D::zero());
let glyph = webrender_traits::GlyphInstance {
diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs
index 00c77631707..86c370c0a83 100644
--- a/components/layout/wrapper.rs
+++ b/components/layout/wrapper.rs
@@ -33,7 +33,7 @@
use core::nonzero::NonZero;
use data::{LayoutDataFlags, PrivateLayoutData};
use gfx::display_list::OpaqueNode;
-use gfx::text::glyph::CharIndex;
+use gfx::text::glyph::ByteIndex;
use gfx_traits::{LayerId, LayerType};
use incremental::RestyleDamage;
use msg::constellation_msg::PipelineId;
@@ -74,7 +74,7 @@ use style::restyle_hints::ElementSnapshot;
use style::selector_impl::{NonTSPseudoClass, PseudoElement, ServoSelectorImpl};
use style::servo::PrivateStyleData;
use url::Url;
-use util::str::{is_whitespace, search_index};
+use util::str::is_whitespace;
pub type NonOpaqueStyleAndLayoutData = *mut RefCell<PrivateLayoutData>;
@@ -838,7 +838,7 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq {
fn text_content(&self) -> TextContent;
/// If the insertion point is within this node, returns it. Otherwise, returns `None`.
- fn selection(&self) -> Option<Range<CharIndex>>;
+ fn selection(&self) -> Option<Range<ByteIndex>>;
/// If this is an image element, returns its URL. If this is not an image element, fails.
///
@@ -1077,27 +1077,18 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
panic!("not text!")
}
- fn selection(&self) -> Option<Range<CharIndex>> {
- let this = unsafe {
- self.get_jsmanaged()
- };
+ fn selection(&self) -> Option<Range<ByteIndex>> {
+ let this = unsafe { self.get_jsmanaged() };
- if let Some(area) = this.downcast::<HTMLTextAreaElement>() {
- if let Some(selection) = unsafe { area.get_absolute_selection_for_layout() } {
- let text = unsafe { area.get_value_for_layout() };
- let begin_byte = selection.begin();
- let begin = search_index(begin_byte, text.char_indices());
- let length = search_index(selection.length(), text[begin_byte..].char_indices());
- return Some(Range::new(CharIndex(begin), CharIndex(length)));
- }
- }
- if let Some(input) = this.downcast::<HTMLInputElement>() {
- if let Some(selection) = unsafe { input.selection_for_layout() } {
- return Some(Range::new(CharIndex(selection.begin()),
- CharIndex(selection.length())));
- }
- }
- None
+ let selection = if let Some(area) = this.downcast::<HTMLTextAreaElement>() {
+ unsafe { area.selection_for_layout() }
+ } else if let Some(input) = this.downcast::<HTMLInputElement>() {
+ unsafe { input.selection_for_layout() }
+ } else {
+ return None;
+ };
+ selection.map(|range| Range::new(ByteIndex(range.start as isize),
+ ByteIndex(range.len() as isize)))
}
fn image_url(&self) -> Option<Url> {