aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeegan McAllister <kmcallister@mozilla.com>2013-08-09 14:43:44 -0700
committerKeegan McAllister <kmcallister@mozilla.com>2013-08-15 13:55:40 -0700
commitabaeb582035e05ecbe1134ec542cda463f808f7a (patch)
tree6c121672e41b6452c964d643d43dd8fed45e321d
parentbe061a9aa0384fc36b42f4f8902b6c8cb76d30cc (diff)
downloadservo-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.rs109
-rw-r--r--src/components/gfx/text/text_run.rs128
-rw-r--r--src/components/main/layout/flow.rs61
-rw-r--r--src/components/main/layout/util.rs21
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]) {