More TextRange refactoring.

This commit is contained in:
Brian J. Burg 2012-10-18 11:31:58 -07:00
parent f9040afada
commit efca6fedfc
2 changed files with 31 additions and 32 deletions

View file

@ -193,41 +193,41 @@ impl RenderBox : RenderBoxMethods {
let mut right_length : Option<uint> = None; let mut right_length : Option<uint> = None;
debug!("split_to_width: splitting text box (strlen=%u, off=%u, len=%u, avail_width=%?)", debug!("split_to_width: splitting text box (strlen=%u, off=%u, len=%u, avail_width=%?)",
data.run.text.len(), data.offset, data.length, max_width); data.run.text.len(), data.offset, data.length, max_width);
do data.run.iter_indivisible_pieces_for_range(TextRange(data.offset, data.length)) |off, len| { do data.run.iter_indivisible_pieces_for_range(TextRange(data.offset, data.length)) |subrange| {
debug!("split_to_width: considering range (off=%u, len=%u, remain_width=%?)", debug!("split_to_width: considering range (off=%u, len=%u, remain_width=%?)",
off, len, remaining_width); subrange.begin(), subrange.length(), remaining_width);
let metrics = data.run.metrics_for_range(TextRange(off, len)); let metrics = data.run.metrics_for_range(subrange);
let advance = metrics.advance_width; let advance = metrics.advance_width;
let should_continue : bool; let should_continue : bool;
if advance <= remaining_width { if advance <= remaining_width {
should_continue = true; should_continue = true;
if starts_line && i == 0 && data.run.range_is_trimmable_whitespace(TextRange(off, len)) { if starts_line && i == 0 && data.run.range_is_trimmable_whitespace(subrange) {
debug!("split_to_width: case=skipping leading trimmable whitespace"); debug!("split_to_width: case=skipping leading trimmable whitespace");
left_offset += len; left_offset += subrange.length();
} else { } else {
debug!("split_to_width: case=enlarging span"); debug!("split_to_width: case=enlarging span");
remaining_width -= advance; remaining_width -= advance;
left_length += len; left_length += subrange.length();
} }
} else { /* advance > remaining_width */ } else { /* advance > remaining_width */
should_continue = false; should_continue = false;
if data.run.range_is_trimmable_whitespace(TextRange(off, len)) { if data.run.range_is_trimmable_whitespace(subrange) {
// if there are still things after the trimmable whitespace, create right chunk // if there are still things after the trimmable whitespace, create right chunk
if off + len < data.offset + data.length { if subrange.end() < data.offset + data.length {
debug!("split_to_width: case=skipping trimmable trailing whitespace, then split remainder"); debug!("split_to_width: case=skipping trimmable trailing whitespace, then split remainder");
right_offset = Some(off + len); right_offset = Some(subrange.end());
right_length = Some((data.offset + data.length) - (off + len)); right_length = Some((data.offset + data.length) - subrange.end());
} else { } else {
debug!("split_to_width: case=skipping trimmable trailing whitespace"); debug!("split_to_width: case=skipping trimmable trailing whitespace");
} }
} else if off < data.length + data.offset { } else if subrange.begin() < data.length + data.offset {
// still things left, create right chunk // still things left, create right chunk
right_offset = Some(off); right_offset = Some(subrange.begin());
right_length = Some((data.offset + data.length) - off); right_length = Some((data.offset + data.length) - subrange.begin());
debug!("split_to_width: case=splitting remainder with right span: (off=%u, len=%u)", debug!("split_to_width: case=splitting remainder with right span: (off=%u, len=%u)",
off, (data.offset + data.length) - off); subrange.begin(), (data.offset + data.length) - subrange.begin());
} }
} }
i += 1; i += 1;
@ -293,12 +293,12 @@ impl RenderBox : RenderBoxMethods {
// factor in min/pref widths of any text runs that it owns. // factor in min/pref widths of any text runs that it owns.
TextBox(_,d) => { TextBox(_,d) => {
let mut max_line_width: au = au(0); let mut max_line_width: au = au(0);
for d.run.iter_natural_lines_for_range(TextRange(d.offset, d.length)) |line_offset, line_len| { for d.run.iter_natural_lines_for_range(TextRange(d.offset, d.length)) |line_range| {
// if the line is a single newline, then len will be zero // if the line is a single newline, then len will be zero
if line_len == 0 { loop } if line_range.length() == 0 { loop }
let mut line_width: au = au(0); let mut line_width: au = au(0);
do d.run.glyphs.iter_glyphs_for_range(line_offset, line_len) |_char_i, glyph| { do d.run.glyphs.iter_glyphs_for_range(line_range.begin(), line_range.length()) |_char_i, glyph| {
line_width += glyph.advance() line_width += glyph.advance()
}; };
max_line_width = au::max(max_line_width, line_width); max_line_width = au::max(max_line_width, line_width);

View file

@ -139,14 +139,14 @@ pub fn deserialize(cache: @FontCache, run: &SendableTextRun) -> @TextRun {
trait TextRunMethods { trait TextRunMethods {
pure fn glyphs(&self) -> &self/GlyphStore; pure fn glyphs(&self) -> &self/GlyphStore;
fn iter_indivisible_pieces_for_range(&self, range: TextRange, f: fn(uint, uint) -> bool); fn iter_indivisible_pieces_for_range(&self, range: TextRange, f: fn&(TextRange) -> bool);
// TODO: needs to take box style as argument, or move to TextBox. // TODO: needs to take box style as argument, or move to TextBox.
// see Gecko's IsTrimmableSpace methods for details. // see Gecko's IsTrimmableSpace methods for details.
pure fn range_is_trimmable_whitespace(&self, range: TextRange) -> bool; pure fn range_is_trimmable_whitespace(&self, range: TextRange) -> bool;
fn metrics_for_range(&self, range: TextRange) -> RunMetrics; fn metrics_for_range(&self, range: TextRange) -> RunMetrics;
fn min_width_for_range(&self, range: TextRange) -> au; fn min_width_for_range(&self, range: TextRange) -> au;
fn iter_natural_lines_for_range(&self, range: TextRange, f: fn(uint, uint) -> bool); fn iter_natural_lines_for_range(&self, range: TextRange, f: fn&(TextRange) -> bool);
} }
impl TextRun : TextRunMethods { impl TextRun : TextRunMethods {
@ -174,14 +174,14 @@ impl TextRun : TextRunMethods {
assert range.is_valid_for_string(self.text); assert range.is_valid_for_string(self.text);
let mut max_piece_width = au(0); let mut max_piece_width = au(0);
for self.iter_indivisible_pieces_for_range(range) |piece_offset, piece_len| { for self.iter_indivisible_pieces_for_range(range) |piece_range| {
let metrics = self.font.measure_text(self, piece_offset, piece_len); let metrics = self.font.measure_text(self, piece_range.begin(), piece_range.length());
max_piece_width = au::max(max_piece_width, metrics.advance_width); max_piece_width = au::max(max_piece_width, metrics.advance_width);
} }
return max_piece_width; return max_piece_width;
} }
fn iter_natural_lines_for_range(&self, range: TextRange, f: fn(uint, uint) -> bool) { fn iter_natural_lines_for_range(&self, range: TextRange, f: fn(TextRange) -> bool) {
assert range.is_valid_for_string(self.text); assert range.is_valid_for_string(self.text);
let clump = MutableTextRange(range.begin(), 0); let clump = MutableTextRange(range.begin(), 0);
@ -197,7 +197,7 @@ impl TextRun : TextRunMethods {
in_clump = false; in_clump = false;
// don't include the linebreak 'glyph' // don't include the linebreak 'glyph'
// (we assume there's one GlyphEntry for a newline, and no actual glyphs) // (we assume there's one GlyphEntry for a newline, and no actual glyphs)
if !f(clump.begin(), clump.length()) { break } if !f(clump.as_immutable()) { break }
} }
} }
} }
@ -205,29 +205,28 @@ impl TextRun : TextRunMethods {
// flush any remaining chars as a line // flush any remaining chars as a line
if in_clump { if in_clump {
clump.extend_to(range.end()); clump.extend_to(range.end());
f(clump.begin(), clump.length()); f(clump.as_immutable());
} }
} }
fn iter_indivisible_pieces_for_range(&self, range: TextRange, f: fn(uint, uint) -> bool) { fn iter_indivisible_pieces_for_range(&self, range: TextRange, f: fn(TextRange) -> bool) {
assert range.is_valid_for_string(self.text); assert range.is_valid_for_string(self.text);
let clump = MutableTextRange(range.begin(), 0); let clump = MutableTextRange(range.begin(), 0);
loop { loop {
// find next non-whitespace byte index, then clump all whitespace before it. // find next non-whitespace byte index, then clump all whitespace before it.
if clump.end() == range.end() { break } if clump.end() == range.end() { break }
match str::find_from(self.text, clump.begin(), |c| !char::is_whitespace(c)) { match str::find_from(self.text, clump.begin(), |c| !char::is_whitespace(c)) {
Some(nonws_char_offset) => { Some(nonws_char_offset) => {
clump.extend_to(nonws_char_offset); clump.extend_to(nonws_char_offset);
if !f(clump.begin(), clump.length()) { break } if !f(clump.as_immutable()) { break }
clump.reset(clump.end(), 0); clump.reset(clump.end(), 0);
}, },
None => { None => {
// nothing left, flush last piece containing only whitespace // nothing left, flush last piece containing only whitespace
if clump.end() < range.end() { if clump.end() < range.end() {
clump.extend_to(range.end()); clump.extend_to(range.end());
f(clump.begin(), clump.length()); f(clump.as_immutable());
} }
} }
}; };
@ -237,14 +236,14 @@ impl TextRun : TextRunMethods {
match str::find_from(self.text, clump.begin(), |c| char::is_whitespace(c)) { match str::find_from(self.text, clump.begin(), |c| char::is_whitespace(c)) {
Some(ws_char_offset) => { Some(ws_char_offset) => {
clump.extend_to(ws_char_offset); clump.extend_to(ws_char_offset);
if !f(clump.begin(), clump.length()) { break } if !f(clump.as_immutable()) { break }
clump.reset(clump.end(), 0); clump.reset(clump.end(), 0);
} }
None => { None => {
// nothing left, flush last piece containing only non-whitespaces // nothing left, flush last piece containing only non-whitespaces
if clump.end() < range.end() { if clump.end() < range.end() {
clump.extend_to(range.end()); clump.extend_to(range.end());
f(clump.begin(), clump.length()); f(clump.as_immutable());
} }
} }
} }
@ -292,8 +291,8 @@ fn test_iter_indivisible_pieces() {
let font = flib.get_test_font(); let font = flib.get_test_font();
let run = TextRun(font, copy text); let run = TextRun(font, copy text);
let mut slices : ~[~str] = ~[]; let mut slices : ~[~str] = ~[];
for run.iter_indivisible_pieces_for_range(TextRange(0, text.len())) |offset, length| { for run.iter_indivisible_pieces_for_range(TextRange(0, text.len())) |subrange| {
slices.push(str::slice(text, offset, length)); slices.push(str::slice(text, subrange.begin(), subrange.length()));
} }
assert slices == res; assert slices == res;
} }