diff options
author | Keegan McAllister <kmcallister@mozilla.com> | 2013-08-09 14:43:44 -0700 |
---|---|---|
committer | Keegan McAllister <kmcallister@mozilla.com> | 2013-08-15 13:55:40 -0700 |
commit | abaeb582035e05ecbe1134ec542cda463f808f7a (patch) | |
tree | 6c121672e41b6452c964d643d43dd8fed45e321d | |
parent | be061a9aa0384fc36b42f4f8902b6c8cb76d30cc (diff) | |
download | servo-abaeb582035e05ecbe1134ec542cda463f808f7a.tar.gz servo-abaeb582035e05ecbe1134ec542cda463f808f7a.zip |
Convert our iterators to external iterators
Except util/tree.rs (see next commit).
-rw-r--r-- | src/components/gfx/text/glyph.rs | 109 | ||||
-rw-r--r-- | src/components/gfx/text/text_run.rs | 128 | ||||
-rw-r--r-- | src/components/main/layout/flow.rs | 61 | ||||
-rw-r--r-- | src/components/main/layout/util.rs | 21 |
4 files changed, 173 insertions, 146 deletions
diff --git a/src/components/gfx/text/glyph.rs b/src/components/gfx/text/glyph.rs index d1373922a51..f1a494409af 100644 --- a/src/components/gfx/text/glyph.rs +++ b/src/components/gfx/text/glyph.rs @@ -14,6 +14,7 @@ use std::u16; use std::vec; use std::uint; use std::util; +use std::iterator; use geom::point::Point2D; use extra::sort; @@ -599,62 +600,24 @@ impl<'self> GlyphStore { self.entry_buffer[i] = entry; } - pub fn iter_glyphs_for_char_index(&'self self, - i: uint, - cb: &fn(uint, &GlyphInfo<'self>) -> bool) - -> bool { - assert!(i < self.entry_buffer.len()); - - let entry = &self.entry_buffer[i]; - match entry.is_simple() { - true => { - let proxy = &SimpleGlyphInfo(self, i); - cb(i, proxy); - }, - false => { - let glyphs = self.detail_store.get_detailed_glyphs_for_entry(i, - entry.glyph_count()); - for uint::range(0, glyphs.len()) |j| { - let proxy = &DetailGlyphInfo(self, i, j as u16); - cb(i, proxy); - } - } - } - true + pub fn iter_glyphs_for_char_index(&'self self, i: uint) -> GlyphIterator<'self> { + self.iter_glyphs_for_char_range(&Range::new(i, 1)) } - pub fn iter_glyphs_for_char_range(&'self self, - range: &Range, - callback: &fn(uint, &GlyphInfo<'self>) -> bool) - -> bool { - if range.begin() >= self.entry_buffer.len() { - error!("iter_glyphs_for_range: range.begin beyond length!"); - return false + pub fn iter_glyphs_for_char_range(&'self self, rang: &Range) -> GlyphIterator<'self> { + if rang.begin() >= self.entry_buffer.len() { + fail!("iter_glyphs_for_range: range.begin beyond length!"); } - if range.end() > self.entry_buffer.len() { - error!("iter_glyphs_for_range: range.end beyond length!"); - return false + if rang.end() > self.entry_buffer.len() { + fail!("iter_glyphs_for_range: range.end beyond length!"); } - for range.eachi |i| { - // FIXME: Work around rust#2202. We should be able to pass the callback directly. - if !self.iter_glyphs_for_char_index(i, |a, b| callback(a, b)) { - break - } - } - - true - } - - pub fn iter_all_glyphs(&'self self, callback: &fn(uint, &GlyphInfo<'self>) -> bool) -> bool { - for uint::range(0, self.entry_buffer.len()) |i| { - // FIXME: Work around rust#2202. We should be able to pass the callback directly. - if !self.iter_glyphs_for_char_index(i, |a, b| callback(a, b)) { - break; - } + GlyphIterator { + store: self, + char_index: rang.begin(), + char_range: rang.eachi(), + glyph_range: None } - - true } // getter methods @@ -713,3 +676,49 @@ impl<'self> GlyphStore { self.entry_buffer[i] = entry.set_can_break_before(t); } } + +pub struct GlyphIterator<'self> { + priv store: &'self GlyphStore, + priv char_index: uint, + priv char_range: iterator::Range<uint>, + priv glyph_range: Option<iterator::Range<uint>>, +} + +impl<'self> Iterator<(uint, GlyphInfo<'self>)> for GlyphIterator<'self> { + // I tried to start with something simpler and apply FlatMap, but the + // inability to store free variables in the FlatMap struct was problematic. + + fn next(&mut self) -> Option<(uint, GlyphInfo<'self>)> { + // Would use 'match' here but it borrows contents in a way that + // interferes with mutation. + if self.glyph_range.is_some() { + match self.glyph_range.unwrap().next() { + Some(j) => Some((self.char_index, + DetailGlyphInfo(self.store, self.char_index, j as u16))), + None => { + // No more glyphs for current character. Try to get another. + self.glyph_range = None; + self.next() + } + } + } else { + // No glyph range. Look at next character. + match self.char_range.next() { + Some(i) => { + self.char_index = i; + assert!(i < self.store.entry_buffer.len()); + let entry = &self.store.entry_buffer[i]; + if entry.is_simple() { + Some((self.char_index, SimpleGlyphInfo(self.store, i))) + } else { + let glyphs = self.store.detail_store + .get_detailed_glyphs_for_entry(i, entry.glyph_count()); + self.glyph_range = Some(range(0, glyphs.len())); + self.next() + } + }, + None => None + } + } + } +} diff --git a/src/components/gfx/text/text_run.rs b/src/components/gfx/text/text_run.rs index d3ea446fcf7..0688cb75b37 100644 --- a/src/components/gfx/text/text_run.rs +++ b/src/components/gfx/text/text_run.rs @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use std::vec::VecIterator; + use font_context::FontContext; use geometry::Au; use text::glyph::GlyphStore; @@ -41,6 +43,78 @@ impl SendableTextRun { } } +pub struct SliceIterator<'self> { + priv glyph_iter: VecIterator<'self, Arc<GlyphStore>>, + priv range: Range, + priv offset: uint, +} + +impl<'self> Iterator<(&'self GlyphStore, uint, Range)> for SliceIterator<'self> { + fn next(&mut self) -> Option<(&'self GlyphStore, uint, Range)> { + loop { + let slice_glyphs = self.glyph_iter.next(); + if slice_glyphs.is_none() { + return None; + } + let slice_glyphs = slice_glyphs.unwrap().get(); + + let slice_range = Range::new(self.offset, slice_glyphs.char_len()); + let mut char_range = self.range.intersect(&slice_range); + char_range.shift_by(-(self.offset.to_int())); + + let old_offset = self.offset; + self.offset += slice_glyphs.char_len(); + if !char_range.is_empty() { + return Some((slice_glyphs, old_offset, char_range)) + } + } + } +} + +pub struct LineIterator<'self> { + priv range: Range, + priv clump: Option<Range>, + priv slices: SliceIterator<'self>, +} + +impl<'self> Iterator<Range> for LineIterator<'self> { + fn next(&mut self) -> Option<Range> { + // Loop until we hit whitespace and are in a clump. + loop { + match self.slices.next() { + Some((glyphs, offset, slice_range)) => { + match (glyphs.is_whitespace(), self.clump) { + (false, Some(ref mut c)) => { + c.extend_by(slice_range.length().to_int()); + } + (false, None) => { + let mut c = slice_range; + c.shift_by(offset.to_int()); + self.clump = Some(c); + } + (true, None) => { /* chomp whitespace */ } + (true, Some(c)) => { + self.clump = None; + // The final whitespace clump is not included. + return Some(c); + } + } + }, + None => { + // flush any remaining chars as a line + if self.clump.is_some() { + let mut c = self.clump.take_unwrap(); + c.extend_to(self.range.end()); + return Some(c); + } else { + return None; + } + } + } + } + } +} + impl<'self> TextRun { pub fn new(font: @mut Font, text: ~str, underline: bool) -> TextRun { let glyphs = TextRun::break_and_shape(font, text); @@ -156,53 +230,19 @@ impl<'self> TextRun { max_piece_width } - pub fn iter_slices_for_range(&self, - range: &Range, - f: &fn(&GlyphStore, uint, &Range) -> bool) - -> bool { - let mut offset = 0; - for self.glyphs.iter().advance |slice_glyphs| { - // Determine the range of this slice that we need. - let slice_range = Range::new(offset, slice_glyphs.get().char_len()); - let mut char_range = range.intersect(&slice_range); - char_range.shift_by(-(offset.to_int())); - - let unwrapped_glyphs = slice_glyphs.get(); - if !char_range.is_empty() { - if !f(unwrapped_glyphs, offset, &char_range) { break } - } - offset += unwrapped_glyphs.char_len(); + pub fn iter_slices_for_range(&'self self, range: &Range) -> SliceIterator<'self> { + SliceIterator { + glyph_iter: self.glyphs.iter(), + range: *range, + offset: 0, } - true } - pub fn iter_natural_lines_for_range(&self, range: &Range, f: &fn(&Range) -> bool) -> bool { - let mut clump = Range::new(range.begin(), 0); - let mut in_clump = false; - - for self.iter_slices_for_range(range) |glyphs, offset, slice_range| { - match (glyphs.is_whitespace(), in_clump) { - (false, true) => { clump.extend_by(slice_range.length().to_int()); } - (false, false) => { - in_clump = true; - clump = *slice_range; - clump.shift_by(offset.to_int()); - } - (true, false) => { /* chomp whitespace */ } - (true, true) => { - in_clump = false; - // The final whitespace clump is not included. - if !f(&clump) { break } - } - } - } - - // flush any remaining chars as a line - if in_clump { - clump.extend_to(range.end()); - f(&clump); + pub fn iter_natural_lines_for_range(&'self self, range: &Range) -> LineIterator<'self> { + LineIterator { + range: *range, + clump: None, + slices: self.iter_slices_for_range(range), } - - true } } diff --git a/src/components/main/layout/flow.rs b/src/components/main/layout/flow.rs index 2d7db5d4a3c..6dc7e9409dc 100644 --- a/src/components/main/layout/flow.rs +++ b/src/components/main/layout/flow.rs @@ -238,6 +238,23 @@ impl TreeNode<FlowContext> for FlowData { } } +pub struct BoxIterator { + priv boxes: ~[RenderBox], + priv index: uint, +} + +impl Iterator<RenderBox> for BoxIterator { + fn next(&mut self) -> Option<RenderBox> { + if self.index >= self.boxes.len() { + None + } else { + let v = self.boxes[self.index].clone(); + self.index += 1; + Some(v) + } + } +} + impl FlowData { pub fn new(id: int, node: AbstractNode<LayoutView>) -> FlowData { FlowData { @@ -408,43 +425,15 @@ impl<'self> FlowContext { } } - pub fn iter_all_boxes(&self, cb: &fn(RenderBox) -> bool) -> bool { - match *self { - BlockFlow(block) => { - let block = &mut *block; - for block.box.iter().advance |box| { - if !cb(*box) { - break; - } - } - } - InlineFlow(inline) => { - let inline = &mut *inline; - for inline.boxes.iter().advance |box| { - if !cb(*box) { - break; - } - } - } - _ => fail!(fmt!("Don't know how to iterate node's RenderBoxes for %?", self)) - } - - true - } - - pub fn iter_boxes_for_node(&self, - node: AbstractNode<LayoutView>, - callback: &fn(RenderBox) -> bool) - -> bool { - for self.iter_all_boxes |box| { - if box.node() == node { - if !callback(box) { - break; - } - } + pub fn iter_all_boxes(&self) -> BoxIterator { + BoxIterator { + boxes: match *self { + BlockFlow (block) => block.box.map_default(~[], |&x| ~[x]), + InlineFlow(inline) => inline.boxes.clone(), + _ => fail!(fmt!("Don't know how to iterate node's RenderBoxes for %?", self)) + }, + index: 0, } - - true } /// Dumps the flow tree for debugging. diff --git a/src/components/main/layout/util.rs b/src/components/main/layout/util.rs index e851cbb41b8..727523529f9 100644 --- a/src/components/main/layout/util.rs +++ b/src/components/main/layout/util.rs @@ -6,6 +6,9 @@ use layout::box::{RenderBox}; use script::dom::node::{AbstractNode, LayoutView}; use servo_util::range::Range; +use std::iterator::Enumerate; +use std::vec::VecIterator; + pub struct NodeRange { node: AbstractNode<LayoutView>, range: Range, @@ -39,22 +42,8 @@ impl ElementMapping { true } - pub fn eachi(&self, callback: &fn(i: uint, nr: &NodeRange) -> bool) -> bool { - for self.entries.iter().enumerate().advance |(i, nr)| { - if !callback(i, nr) { - break - } - } - true - } - - pub fn eachi_mut(&self, callback: &fn(i: uint, nr: &NodeRange) -> bool) -> bool { - for self.entries.iter().enumerate().advance |(i, nr)| { - if !callback(i, nr) { - break - } - } - true + pub fn eachi<'a>(&'a self) -> Enumerate<VecIterator<'a, NodeRange>> { + self.entries.iter().enumerate() } pub fn repair_for_box_changes(&mut self, old_boxes: &[RenderBox], new_boxes: &[RenderBox]) { |