Convert our iterators to external iterators

Except util/tree.rs (see next commit).
This commit is contained in:
Keegan McAllister 2013-08-09 14:43:44 -07:00
parent be061a9aa0
commit abaeb58203
4 changed files with 173 additions and 146 deletions

View file

@ -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
}
GlyphIterator {
store: self,
char_index: rang.begin(),
char_range: rang.eachi(),
glyph_range: None
}
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;
}
}
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
}
}
}
}

View file

@ -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 }
}
}
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),
}
// flush any remaining chars as a line
if in_clump {
clump.extend_to(range.end());
f(&clump);
}
true
}
}

View file

@ -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))
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
}
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;
}
}
}
true
}
/// Dumps the flow tree for debugging.

View file

@ -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]) {