Finish conversion to using only character ranges. We don't crash on multi-byte characters any more.

This commit is contained in:
Brian J. Burg 2012-11-21 17:46:33 -08:00
parent ddb4e5e17d
commit 29e46273f9
4 changed files with 31 additions and 30 deletions

View file

@ -631,12 +631,8 @@ impl GlyphStore {
} }
pure fn char_is_newline(i: uint) -> bool { pure fn char_is_newline(i: uint) -> bool {
if i >= self.entry_buffer.len() { assert i < self.entry_buffer.len();
error!("char_is_newline: beyond entry buffer!"); self.entry_buffer[i].char_is_newline()
false
} else {
self.entry_buffer[i].char_is_newline()
}
} }
pure fn is_ligature_start(i: uint) -> bool { pure fn is_ligature_start(i: uint) -> bool {

View file

@ -59,15 +59,16 @@ impl TextRun {
static fn compute_potential_breaks(text: &str, glyphs: &mut GlyphStore) { static fn compute_potential_breaks(text: &str, glyphs: &mut GlyphStore) {
// TODO(Issue #230): do a better job. See Gecko's LineBreaker. // TODO(Issue #230): do a better job. See Gecko's LineBreaker.
let mut i = 0u; let mut byte_i = 0u;
let mut char_j = 0u;
let mut prev_is_whitespace = false; let mut prev_is_whitespace = false;
while i < text.len() { while byte_i < text.len() {
let {ch, next} = str::char_range_at(text, i); let {ch, next} = str::char_range_at(text, byte_i);
// set char properties. // set char properties.
match ch { match ch {
' ' => { glyphs.set_char_is_space(i); }, ' ' => { glyphs.set_char_is_space(char_j); },
'\t' => { glyphs.set_char_is_tab(i); }, '\t' => { glyphs.set_char_is_tab(char_j); },
'\n' => { glyphs.set_char_is_newline(i); }, '\n' => { glyphs.set_char_is_newline(char_j); },
_ => {} _ => {}
} }
@ -76,21 +77,22 @@ impl TextRun {
match ch { match ch {
' ' | '\t' | '\n' => {}, ' ' | '\t' | '\n' => {},
_ => { _ => {
glyphs.set_can_break_before(i, BreakTypeNormal); glyphs.set_can_break_before(char_j, BreakTypeNormal);
prev_is_whitespace = false; prev_is_whitespace = false;
} }
} }
} else { } else {
match ch { match ch {
' ' | '\t' | '\n' => { ' ' | '\t' | '\n' => {
glyphs.set_can_break_before(i, BreakTypeNormal); glyphs.set_can_break_before(char_j, BreakTypeNormal);
prev_is_whitespace = true; prev_is_whitespace = true;
}, },
_ => { } _ => { }
} }
} }
i = next; byte_i = next;
char_j += 1;
} }
} }
@ -102,18 +104,14 @@ impl TextRun {
} }
} }
pure fn char_len() -> uint { self.glyphs.entry_buffer.len() }
pure fn glyphs(&self) -> &self/GlyphStore { &self.glyphs } pure fn glyphs(&self) -> &self/GlyphStore { &self.glyphs }
pure fn range_is_trimmable_whitespace(&self, range: &const Range) -> bool { pure fn range_is_trimmable_whitespace(&self, range: &const Range) -> bool {
let mut i = range.begin(); for range.eachi |i| {
while i < range.end() { if !self.glyphs.char_is_space(i) &&
// jump i to each new char !self.glyphs.char_is_tab(i) &&
let {ch, next} = str::char_range_at(self.text, i); !self.glyphs.char_is_newline(i) { return false; }
match ch {
' ' | '\t' | '\r' => {},
_ => { return false; }
}
i = next;
} }
return true; return true;
} }
@ -124,7 +122,9 @@ impl TextRun {
fn min_width_for_range(&self, range: &const Range) -> Au { fn min_width_for_range(&self, range: &const Range) -> Au {
let mut max_piece_width = Au(0); let mut max_piece_width = Au(0);
debug!("iterating outer range %?", range);
for self.iter_indivisible_pieces_for_range(range) |piece_range| { for self.iter_indivisible_pieces_for_range(range) |piece_range| {
debug!("iterated on %?", piece_range);
let metrics = self.font.measure_text(self, piece_range); let metrics = self.font.measure_text(self, piece_range);
max_piece_width = Au::max(max_piece_width, metrics.advance_width); max_piece_width = Au::max(max_piece_width, metrics.advance_width);
} }

View file

@ -246,7 +246,7 @@ priv impl TextRunScanner {
debug!("TextRunScanner: pushing single text box in range: %?", self.clump); debug!("TextRunScanner: pushing single text box in range: %?", self.clump);
let new_box = layout::text::adapt_textbox_with_range(old_box.d(), let new_box = layout::text::adapt_textbox_with_range(old_box.d(),
run, run,
&const Range::new(0, run.text.len())); &const Range::new(0, run.char_len()));
out_boxes.push(new_box); out_boxes.push(new_box);
}, },
(false, true) => { (false, true) => {
@ -263,14 +263,15 @@ priv impl TextRunScanner {
transform_text(in_boxes[idx].raw_text(), compression) transform_text(in_boxes[idx].raw_text(), compression)
}); });
// next, concatenate all of the transformed strings together, saving the new text indices // next, concatenate all of the transformed strings together, saving the new char indices
// TODO(Issue #118): use a rope, simply give ownership of nonzero strs to rope
let mut run_str : ~str = ~""; let mut run_str : ~str = ~"";
let new_ranges : DVec<Range> = DVec(); let new_ranges : DVec<Range> = DVec();
let mut char_total = 0u;
for uint::range(0, transformed_strs.len()) |i| { for uint::range(0, transformed_strs.len()) |i| {
new_ranges.push(Range::new(run_str.len(), transformed_strs[i].len())); let added_chars = str::char_len(transformed_strs[i]);
new_ranges.push(Range::new(char_total, added_chars));
str::push_str(&mut run_str, transformed_strs[i]); str::push_str(&mut run_str, transformed_strs[i]);
char_total += added_chars;
} }
// create the run, then make new boxes with the run and adjusted text indices // create the run, then make new boxes with the run and adjusted text indices

View file

@ -19,8 +19,12 @@ pub fn TextBoxData(run: @TextRun, range: &const Range) -> TextBoxData {
pub fn adapt_textbox_with_range(box_data: &RenderBoxData, run: @TextRun, pub fn adapt_textbox_with_range(box_data: &RenderBoxData, run: @TextRun,
range: &const Range) -> @RenderBox { range: &const Range) -> @RenderBox {
assert range.begin() < run.char_len();
assert range.end() <= run.char_len();
assert range.length() > 0;
debug!("Creating textbox with span: (strlen=%u, off=%u, len=%u) of textrun: %s", debug!("Creating textbox with span: (strlen=%u, off=%u, len=%u) of textrun: %s",
run.text.len(), range.begin(), range.length(), run.text); run.char_len(), range.begin(), range.length(), run.text);
let new_box_data = copy *box_data; let new_box_data = copy *box_data;
let new_text_data = TextBoxData(run, range); let new_text_data = TextBoxData(run, range);
let metrics = run.metrics_for_range(range); let metrics = run.metrics_for_range(range);