diff --git a/src/components/main/layout/construct.rs b/src/components/main/layout/construct.rs
index 869d4af0aeb..e84fa3e7350 100644
--- a/src/components/main/layout/construct.rs
+++ b/src/components/main/layout/construct.rs
@@ -185,7 +185,7 @@ impl InlineFragmentsAccumulator {
fn from_inline_node(node: &ThreadSafeLayoutNode) -> InlineFragmentsAccumulator {
let mut fragments = InlineFragments::new();
- fragments.map.push(node.style().clone(), Range::empty());
+ fragments.push_range(node.style().clone(), Range::empty());
InlineFragmentsAccumulator {
fragments: fragments,
has_enclosing_range: true,
@@ -200,7 +200,7 @@ impl InlineFragmentsAccumulator {
if has_enclosing_range {
let len = FragmentIndex(fragments.len() as int);
- fragments.map.get_mut(FragmentIndex(0)).range.extend_to(len);
+ fragments.get_mut_range(FragmentIndex(0)).range.extend_to(len);
}
fragments
}
@@ -307,23 +307,17 @@ impl<'a> FlowConstructor<'a> {
whitespace_stripping: WhitespaceStrippingMode,
node: &ThreadSafeLayoutNode) {
let mut fragments = fragment_accumulator.finish();
- if fragments.len() == 0 {
- return
- }
+ if fragments.is_empty() { return };
match whitespace_stripping {
NoWhitespaceStripping => {}
StripWhitespaceFromStart => {
- strip_ignorable_whitespace_from_start(&mut fragments);
- if fragments.len() == 0 {
- return
- }
+ fragments.strip_ignorable_whitespace_from_start();
+ if fragments.is_empty() { return };
}
StripWhitespaceFromEnd => {
- strip_ignorable_whitespace_from_end(&mut fragments);
- if fragments.len() == 0 {
- return
- }
+ fragments.strip_ignorable_whitespace_from_end();
+ if fragments.is_empty() { return };
}
}
@@ -1084,58 +1078,3 @@ impl<'ln> ObjectElement for ThreadSafeLayoutNode<'ln> {
}
}
}
-
-/// Strips ignorable whitespace from the start of a list of fragments.
-fn strip_ignorable_whitespace_from_start(fragments: &mut InlineFragments) {
- if fragments.len() == 0 {
- return
- }
-
- let InlineFragments {
- fragments: old_fragments,
- map: mut map
- } = mem::replace(fragments, InlineFragments::new());
-
- // FIXME(#2264, pcwalton): This is slow because vector shift is broken. :(
- let mut found_nonwhitespace = false;
- let mut new_fragments = Vec::new();
- for fragment in old_fragments.iter() {
- if !found_nonwhitespace && fragment.is_whitespace_only() {
- debug!("stripping ignorable whitespace from start");
- continue
- }
-
- found_nonwhitespace = true;
- new_fragments.push(fragment.clone())
- }
-
- map.fixup(old_fragments.as_slice(), new_fragments.as_slice());
- *fragments = InlineFragments {
- fragments: new_fragments,
- map: map,
- }
-}
-
-/// Strips ignorable whitespace from the end of a list of fragments.
-fn strip_ignorable_whitespace_from_end(fragments: &mut InlineFragments) {
- if fragments.len() == 0 {
- return
- }
-
- let InlineFragments {
- fragments: old_fragments,
- map: mut map
- } = mem::replace(fragments, InlineFragments::new());
-
- let mut new_fragments = old_fragments.clone();
- while new_fragments.len() > 0 && new_fragments.as_slice().last().get_ref().is_whitespace_only() {
- debug!("stripping ignorable whitespace from end");
- drop(new_fragments.pop());
- }
-
- map.fixup(old_fragments.as_slice(), new_fragments.as_slice());
- *fragments = InlineFragments {
- fragments: new_fragments,
- map: map,
- }
-}
diff --git a/src/components/main/layout/inline.rs b/src/components/main/layout/inline.rs
index b2eaf777bde..01d544c3ec0 100644
--- a/src/components/main/layout/inline.rs
+++ b/src/components/main/layout/inline.rs
@@ -82,12 +82,62 @@ pub struct Line {
/// The ranges that describe these lines would be:
///
/// ~~~
- /// | [0.0, 1.4) | [1.5, 2.0) | [2.0, 3.4) | [3.4, 4.0) |
- /// |------------|-------------|-------------|-------------|
- /// | 'I like' | 'truffles,' | '
yes' | 'yes I do.' |
+ /// | [0.0, 1.4) | [1.5, 2.0) | [2.0, 3.4) | [3.4, 4.0) |
+ /// |------------|-------------|-------------|------------|
+ /// | 'I like' | 'truffles,' | '
yes' | 'I do.' |
/// ~~~
pub range: Range,
+ /// The bounds are the exact position and extents of the line with respect
+ /// to the parent box.
+ ///
+ /// For example, for the HTML below...
+ ///
+ /// ~~~html
+ /// I like truffles, ![]()
+ /// ~~~
+ ///
+ /// ...the bounds would be:
+ ///
+ /// ~~~
+ /// +-----------------------------------------------------------+
+ /// | ^ |
+ /// | | |
+ /// | origin.y |
+ /// | | |
+ /// | v |
+ /// |< - origin.x ->+ - - - - - - - - +---------+---- |
+ /// | | | | ^ |
+ /// | | |
| size.height |
+ /// | I like truffles, | | v |
+ /// | + - - - - - - - - +---------+---- |
+ /// | | | |
+ /// | |<------ size.width ------->| |
+ /// | |
+ /// | |
+ /// +-----------------------------------------------------------+
+ /// ~~~
pub bounds: Rect,
+ /// The green zone is the greatest extent from wich a line can extend to
+ /// before it collides with a float.
+ ///
+ /// ~~~
+ /// +-----------------------+
+ /// |::::::::::::::::: |
+ /// |:::::::::::::::::FFFFFF|
+ /// |============:::::FFFFFF|
+ /// |:::::::::::::::::FFFFFF|
+ /// |:::::::::::::::::FFFFFF|
+ /// |::::::::::::::::: |
+ /// | FFFFFFFFF |
+ /// | FFFFFFFFF |
+ /// | FFFFFFFFF |
+ /// | |
+ /// +-----------------------+
+ ///
+ /// === line
+ /// ::: green zone
+ /// FFF float
+ /// ~~~
pub green_zone: Size2D
}
@@ -105,7 +155,7 @@ pub struct LineIndices {
///
/// For example, given the HTML below:
///
- /// ~~~
+ /// ~~~html
/// I like truffles,
yes I do.
/// ~~~
///
@@ -117,27 +167,26 @@ pub struct LineIndices {
/// | 'I ' | 'like truffles,' |
| ' yes I do.' |
/// ~~~
pub fragment_index: FragmentIndex,
-
/// The index of a character in a DOM fragment. Continuous runs of whitespace
- /// are treated as single characters. Non-breakable DOM
- /// fragments such as images are treated as having a range length of `1`.
+ /// are treated as single characters. Non-breakable DOM fragments such as
+ /// images are treated as having a range length of `1`.
///
/// For example, given the HTML below:
///
- /// ~~~
+ /// ~~~html
/// I like truffles,
yes I do.
/// ~~~
///
/// The characters would be indexed as follows:
///
/// ~~~
- /// | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
- /// |---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|----|
- /// | I | | l | i | k | e | e | l | i | k | e | | t | r | u | f | f | l |
+ /// | 0 | 1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
+ /// |---|---|---|---|---|---|---|---|---|---|---|---|----|----|----|----|----|
+ /// | I | | l | i | k | e | | t | r | u | f | f | l | e | s | , | |
///
- /// | 11 | 12 | 13 | 14 | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
- /// |----|----|----|----|-------|---|---|---|---|---|---|---|---|---|---|
- /// | e | s | , | |
| | y | e | s | | I | | d | o | . |
+ /// | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
+ /// |-------|---|---|---|---|---|---|---|---|---|---|
+ /// |
| | y | e | s | | I | | d | o | . |
/// ~~~
pub char_index: CharIndex,
}
@@ -252,57 +301,51 @@ impl LineBreaker {
pub fn scan_for_lines(&mut self, flow: &mut InlineFlow) {
self.reset_scanner();
- // Swap out temporarily.
- let InlineFragments {
- fragments: old_fragments,
- map: mut map
- } = mem::replace(&mut flow.fragments, InlineFragments::new());
+ let mut old_fragments = mem::replace(&mut flow.fragments, InlineFragments::new());
- let mut old_fragment_iter = old_fragments.iter();
- loop {
- // acquire the next fragment to lay out from work list or fragment list
- let cur_fragment = if self.work_list.is_empty() {
- match old_fragment_iter.next() {
- None => break,
- Some(fragment) => {
- debug!("LineBreaker: Working with fragment from flow: b{}",
- fragment.debug_id());
- (*fragment).clone()
+ { // Enter a new scope so that old_fragment_iter's borrow is released
+ let mut old_fragment_iter = old_fragments.fragments.iter();
+ loop {
+ // acquire the next fragment to lay out from work list or fragment list
+ let cur_fragment = if self.work_list.is_empty() {
+ match old_fragment_iter.next() {
+ None => break,
+ Some(fragment) => {
+ debug!("LineBreaker: Working with fragment from flow: b{}",
+ fragment.debug_id());
+ (*fragment).clone()
+ }
}
+ } else {
+ let fragment = self.work_list.pop_front().unwrap();
+ debug!("LineBreaker: Working with fragment from work list: b{}",
+ fragment.debug_id());
+ fragment
+ };
+
+ let fragment_was_appended = match cur_fragment.white_space() {
+ white_space::normal => self.try_append_to_line(cur_fragment, flow),
+ white_space::pre => self.try_append_to_line_by_new_line(cur_fragment),
+ };
+
+ if !fragment_was_appended {
+ debug!("LineBreaker: Fragment wasn't appended, because line {:u} was full.",
+ self.lines.len());
+ self.flush_current_line();
+ } else {
+ debug!("LineBreaker: appended a fragment to line {:u}", self.lines.len());
}
- } else {
- let fragment = self.work_list.pop_front().unwrap();
- debug!("LineBreaker: Working with fragment from work list: b{}",
- fragment.debug_id());
- fragment
- };
+ }
- let fragment_was_appended = match cur_fragment.white_space() {
- white_space::normal => self.try_append_to_line(cur_fragment, flow),
- white_space::pre => self.try_append_to_line_by_new_line(cur_fragment),
- };
-
- if !fragment_was_appended {
- debug!("LineBreaker: Fragment wasn't appended, because line {:u} was full.",
+ if self.pending_line.range.length() > num::zero() {
+ debug!("LineBreaker: Partially full line {:u} left at end of scanning.",
self.lines.len());
self.flush_current_line();
- } else {
- debug!("LineBreaker: appended a fragment to line {:u}", self.lines.len());
}
}
- if self.pending_line.range.length() > num::zero() {
- debug!("LineBreaker: Partially full line {:u} left at end of scanning.",
- self.lines.len());
- self.flush_current_line();
- }
-
- map.fixup(old_fragments.as_slice(), self.new_fragments.as_slice());
- flow.fragments = InlineFragments {
- fragments: mem::replace(&mut self.new_fragments, Vec::new()),
- map: map,
- };
-
+ old_fragments.fixup(mem::replace(&mut self.new_fragments, vec![]));
+ flow.fragments = old_fragments;
flow.lines = mem::replace(&mut self.lines, Vec::new());
}
@@ -588,7 +631,7 @@ impl LineBreaker {
/// Iterator over fragments.
pub struct FragmentIterator<'a> {
iter: Enumerate>,
- map: &'a InlineFragmentMap,
+ ranges: &'a Vec,
}
impl<'a> Iterator<(&'a Fragment, InlineFragmentContext<'a>)> for FragmentIterator<'a> {
@@ -598,7 +641,7 @@ impl<'a> Iterator<(&'a Fragment, InlineFragmentContext<'a>)> for FragmentIterato
None => None,
Some((i, fragment)) => Some((
fragment,
- InlineFragmentContext::new(self.map, FragmentIndex(i as int)),
+ InlineFragmentContext::new(self.ranges, FragmentIndex(i as int)),
)),
}
}
@@ -607,7 +650,7 @@ impl<'a> Iterator<(&'a Fragment, InlineFragmentContext<'a>)> for FragmentIterato
/// Mutable iterator over fragments.
pub struct MutFragmentIterator<'a> {
iter: Enumerate>,
- map: &'a InlineFragmentMap,
+ ranges: &'a Vec,
}
impl<'a> Iterator<(&'a mut Fragment, InlineFragmentContext<'a>)> for MutFragmentIterator<'a> {
@@ -617,7 +660,7 @@ impl<'a> Iterator<(&'a mut Fragment, InlineFragmentContext<'a>)> for MutFragment
None => None,
Some((i, fragment)) => Some((
fragment,
- InlineFragmentContext::new(self.map, FragmentIndex(i as int)),
+ InlineFragmentContext::new(self.ranges, FragmentIndex(i as int)),
)),
}
}
@@ -627,16 +670,17 @@ impl<'a> Iterator<(&'a mut Fragment, InlineFragmentContext<'a>)> for MutFragment
pub struct InlineFragments {
/// The fragments themselves.
pub fragments: Vec,
- /// Tracks the elements that made up the fragments above.
- pub map: InlineFragmentMap,
+ /// Tracks the elements that made up the fragments above. This is used to
+ /// recover the DOM structure from the `fragments` when it's needed.
+ pub ranges: Vec,
}
impl InlineFragments {
/// Creates an empty set of inline fragments.
pub fn new() -> InlineFragments {
InlineFragments {
- fragments: Vec::new(),
- map: InlineFragmentMap::new(),
+ fragments: vec![],
+ ranges: vec![],
}
}
@@ -652,26 +696,24 @@ impl InlineFragments {
/// Pushes a new inline fragment.
pub fn push(&mut self, fragment: Fragment, style: Arc) {
- self.map.push(style, Range::new(FragmentIndex(self.fragments.len() as int), FragmentIndex(1)));
+ self.ranges.push(InlineFragmentRange::new(
+ style, Range::new(FragmentIndex(self.fragments.len() as int), FragmentIndex(1)),
+ ));
self.fragments.push(fragment)
}
/// Merges another set of inline fragments with this one.
- pub fn push_all(&mut self, other: InlineFragments) {
- let InlineFragments {
- fragments: other_fragments,
- map: other_map
- } = other;
+ pub fn push_all(&mut self, InlineFragments { fragments, ranges }: InlineFragments) {
let adjustment = FragmentIndex(self.fragments.len() as int);
- self.map.push_all(other_map, adjustment);
- self.fragments.push_all_move(other_fragments);
+ self.push_all_ranges(ranges, adjustment);
+ self.fragments.push_all_move(fragments);
}
/// Returns an iterator that iterates over all fragments along with the appropriate context.
pub fn iter<'a>(&'a self) -> FragmentIterator<'a> {
FragmentIterator {
iter: self.fragments.as_slice().iter().enumerate(),
- map: &self.map,
+ ranges: &self.ranges,
}
}
@@ -680,7 +722,7 @@ impl InlineFragments {
pub fn mut_iter<'a>(&'a mut self) -> MutFragmentIterator<'a> {
MutFragmentIterator {
iter: self.fragments.as_mut_slice().mut_iter().enumerate(),
- map: &self.map,
+ ranges: &self.ranges,
}
}
@@ -693,6 +735,171 @@ impl InlineFragments {
pub fn get_mut<'a>(&'a mut self, index: uint) -> &'a mut Fragment {
self.fragments.get_mut(index)
}
+
+ /// Adds the given node to the fragment map.
+ pub fn push_range(&mut self, style: Arc, range: Range) {
+ self.ranges.push(InlineFragmentRange::new(style, range))
+ }
+
+ /// Pushes the ranges in a fragment map, adjusting indices as necessary.
+ fn push_all_ranges(&mut self, ranges: Vec, adjustment: FragmentIndex) {
+ for other_range in ranges.move_iter() {
+ let InlineFragmentRange {
+ style: other_style,
+ range: mut other_range
+ } = other_range;
+
+ other_range.shift_by(adjustment);
+ self.push_range(other_style, other_range)
+ }
+ }
+
+ /// Returns the range with the given index.
+ pub fn get_mut_range<'a>(&'a mut self, index: FragmentIndex) -> &'a mut InlineFragmentRange {
+ self.ranges.get_mut(index.to_uint())
+ }
+
+ /// Rebuilds the list after the fragments have been split or deleted (for example, for line
+ /// breaking). This assumes that the overall structure of the DOM has not changed; if the
+ /// DOM has changed, then the flow constructor will need to do more complicated surgery than
+ /// this function can provide.
+ ///
+ /// FIXME(#2267, pcwalton): It would be more efficient to not have to clone fragments all the time;
+ /// i.e. if `self.fragments` contained less info than the entire range of fragments. See
+ /// `layout::construct::strip_ignorable_whitespace_from_start` for an example of some code that
+ /// needlessly has to clone fragments.
+ pub fn fixup(&mut self, new_fragments: Vec) {
+ // TODO(pcwalton): Post Rust upgrade, use `with_capacity` here.
+ let old_list = mem::replace(&mut self.ranges, vec![]);
+ let mut worklist = vec![]; // FIXME(#2269, pcwalton): was smallvec4
+ let mut old_list_iter = old_list.move_iter().peekable();
+
+ { // Enter a new scope so that new_fragments_iter's borrow is released
+ let mut new_fragments_iter = new_fragments.iter().enumerate().peekable();
+ // FIXME(#2270, pcwalton): I don't think this will work if multiple old fragments
+ // correspond to the same node.
+ for (i, old_fragment) in self.fragments.iter().enumerate() {
+ let old_fragment_index = FragmentIndex(i as int);
+ // Find the start of the corresponding new fragment.
+ let new_fragment_start = match new_fragments_iter.peek() {
+ Some(&(index, new_fragment)) if new_fragment.node == old_fragment.node => {
+ // We found the start of the corresponding new fragment.
+ FragmentIndex(index as int)
+ }
+ Some(_) | None => {
+ // The old fragment got deleted entirely.
+ continue
+ }
+ };
+ drop(new_fragments_iter.next());
+
+ // Eat any additional fragments that the old fragment got split into.
+ loop {
+ match new_fragments_iter.peek() {
+ Some(&(_, new_fragment)) if new_fragment.node == old_fragment.node => {}
+ Some(_) | None => break,
+ }
+ drop(new_fragments_iter.next());
+ }
+
+ // Find all ranges that started at this old fragment and add them onto the worklist.
+ loop {
+ match old_list_iter.peek() {
+ None => break,
+ Some(fragment_range) => {
+ if fragment_range.range.begin() > old_fragment_index {
+ // We haven't gotten to the appropriate old fragment yet, so stop.
+ break
+ }
+ // Note that it can be the case that `fragment_range.range.begin() < i`.
+ // This is OK, as it corresponds to the case in which a fragment got
+ // deleted entirely (e.g. ignorable whitespace got nuked). In that case we
+ // want to keep the range, but shorten it.
+ }
+ };
+
+ let InlineFragmentRange {
+ style: style,
+ range: old_range,
+ } = old_list_iter.next().unwrap();
+ worklist.push(InlineFragmentFixupWorkItem {
+ style: style,
+ new_start_index: new_fragment_start,
+ old_end_index: old_range.end(),
+ });
+ }
+
+ // Pop off any ranges that ended at this fragment.
+ loop {
+ match worklist.as_slice().last() {
+ None => break,
+ Some(last_work_item) => {
+ if last_work_item.old_end_index > old_fragment_index + FragmentIndex(1) {
+ // Haven't gotten to it yet.
+ break
+ }
+ }
+ }
+
+ let new_last_index = match new_fragments_iter.peek() {
+ None => {
+ // At the end.
+ FragmentIndex(new_fragments.len() as int)
+ }
+ Some(&(index, _)) => {
+ FragmentIndex(index as int)
+ },
+ };
+
+ let InlineFragmentFixupWorkItem {
+ style,
+ new_start_index,
+ ..
+ } = worklist.pop().unwrap();
+ let range = Range::new(new_start_index, new_last_index - new_start_index);
+ self.ranges.push(InlineFragmentRange::new(style, range))
+ }
+ }
+ }
+ self.fragments = new_fragments;
+ }
+
+ /// Strips ignorable whitespace from the start of a list of fragments.
+ pub fn strip_ignorable_whitespace_from_start(&mut self) {
+ if self.is_empty() {
+ return;
+ }
+
+ // FIXME(#2264, pcwalton): This is slow because vector shift is broken. :(
+ let mut found_nonwhitespace = false;
+ let mut new_fragments = Vec::new();
+ for fragment in self.fragments.iter() {
+ if !found_nonwhitespace && fragment.is_whitespace_only() {
+ debug!("stripping ignorable whitespace from start");
+ continue;
+ }
+
+ found_nonwhitespace = true;
+ new_fragments.push(fragment.clone())
+ }
+
+ self.fixup(new_fragments);
+ }
+
+ /// Strips ignorable whitespace from the end of a list of fragments.
+ pub fn strip_ignorable_whitespace_from_end(&mut self) {
+ if self.is_empty() {
+ return;
+ }
+
+ let mut new_fragments = self.fragments.clone();
+ while new_fragments.len() > 0 && new_fragments.as_slice().last().get_ref().is_whitespace_only() {
+ debug!("stripping ignorable whitespace from end");
+ drop(new_fragments.pop());
+ }
+
+ self.fixup(new_fragments);
+ }
}
/// Flows for inline layout.
@@ -1172,178 +1379,29 @@ impl<'a> Iterator<&'a InlineFragmentRange> for RangeIterator<'a> {
}
}
-/// Information that inline flows keep about nested elements. This is used to recover the DOM
-/// structure from the flat fragment list when it's needed.
-pub struct InlineFragmentMap {
- list: Vec,
-}
-
-impl InlineFragmentMap {
- /// Creates a new fragment map.
- pub fn new() -> InlineFragmentMap {
- InlineFragmentMap {
- list: Vec::new(),
- }
- }
-
- /// Adds the given node to the fragment map.
- pub fn push(&mut self, style: Arc, range: Range) {
- self.list.push(InlineFragmentRange::new(style, range))
- }
-
- /// Pushes the ranges in another fragment map onto the end of this one, adjusting indices as
- /// necessary.
- fn push_all(&mut self, other: InlineFragmentMap, adjustment: FragmentIndex) {
- let InlineFragmentMap {
- list: other_list
- } = other;
-
- for other_range in other_list.move_iter() {
- let InlineFragmentRange {
- style: other_style,
- range: mut other_range
- } = other_range;
-
- other_range.shift_by(adjustment);
- self.push(other_style, other_range)
- }
- }
-
- /// Returns the range with the given index.
- pub fn get_mut<'a>(&'a mut self, index: FragmentIndex) -> &'a mut InlineFragmentRange {
- &mut self.list.as_mut_slice()[index.to_uint()]
- }
-
- /// Iterates over all ranges that contain the fragment with the given index, outermost first.
- #[inline(always)]
- fn ranges_for_index<'a>(&'a self, index: FragmentIndex) -> RangeIterator<'a> {
- RangeIterator {
- iter: self.list.as_slice().iter(),
- index: index,
- seen_first: false,
- }
- }
-
- /// Rebuilds the list after the fragments have been split or deleted (for example, for line
- /// breaking). This assumes that the overall structure of the DOM has not changed; if the
- /// DOM has changed, then the flow constructor will need to do more complicated surgery than
- /// this function can provide.
- ///
- /// FIXME(#2267, pcwalton): It would be more efficient to not have to clone fragments all the time;
- /// i.e. if `old_fragments` contained less info than the entire range of fragments. See
- /// `layout::construct::strip_ignorable_whitespace_from_start` for an example of some code that
- /// needlessly has to clone fragments.
- pub fn fixup(&mut self, old_fragments: &[Fragment], new_fragments: &[Fragment]) {
- // TODO(pcwalton): Post Rust upgrade, use `with_capacity` here.
- let old_list = mem::replace(&mut self.list, Vec::new());
- let mut worklist = Vec::new(); // FIXME(#2269, pcwalton): was smallvec4
- let mut old_list_iter = old_list.move_iter().peekable();
- let mut new_fragments_iter = new_fragments.iter().enumerate().peekable();
-
- // FIXME(#2270, pcwalton): I don't think this will work if multiple old fragments
- // correspond to the same node.
- for (i, old_fragment) in old_fragments.iter().enumerate() {
- let old_fragment_index = FragmentIndex(i as int);
- // Find the start of the corresponding new fragment.
- let new_fragment_start = match new_fragments_iter.peek() {
- Some(&(index, new_fragment)) if new_fragment.node == old_fragment.node => {
- // We found the start of the corresponding new fragment.
- FragmentIndex(index as int)
- }
- Some(_) | None => {
- // The old fragment got deleted entirely.
- continue
- }
- };
- drop(new_fragments_iter.next());
-
- // Eat any additional fragments that the old fragment got split into.
- loop {
- match new_fragments_iter.peek() {
- Some(&(_, new_fragment)) if new_fragment.node == old_fragment.node => {}
- Some(_) | None => break,
- }
- drop(new_fragments_iter.next());
- }
-
- // Find all ranges that started at this old fragment and add them onto the worklist.
- loop {
- match old_list_iter.peek() {
- None => break,
- Some(fragment_range) => {
- if fragment_range.range.begin() > old_fragment_index {
- // We haven't gotten to the appropriate old fragment yet, so stop.
- break
- }
- // Note that it can be the case that `fragment_range.range.begin() < i`.
- // This is OK, as it corresponds to the case in which a fragment got
- // deleted entirely (e.g. ignorable whitespace got nuked). In that case we
- // want to keep the range, but shorten it.
- }
- };
-
- let InlineFragmentRange {
- style: style,
- range: old_range,
- } = old_list_iter.next().unwrap();
- worklist.push(InlineFragmentFixupWorkItem {
- style: style,
- new_start_index: new_fragment_start,
- old_end_index: old_range.end(),
- });
- }
-
- // Pop off any ranges that ended at this fragment.
- loop {
- match worklist.as_slice().last() {
- None => break,
- Some(last_work_item) => {
- if last_work_item.old_end_index > old_fragment_index + FragmentIndex(1) {
- // Haven't gotten to it yet.
- break
- }
- }
- }
-
- let new_last_index = match new_fragments_iter.peek() {
- None => {
- // At the end.
- FragmentIndex(new_fragments.len() as int)
- }
- Some(&(index, _)) => {
- FragmentIndex(index as int)
- },
- };
-
- let InlineFragmentFixupWorkItem {
- style,
- new_start_index,
- ..
- } = worklist.pop().unwrap();
- let range = Range::new(new_start_index, new_last_index - new_start_index);
- self.list.push(InlineFragmentRange::new(style, range))
- }
- }
- }
-}
-
/// The context that an inline fragment appears in. This allows the fragment map to be passed in
/// conveniently to various fragment functions.
pub struct InlineFragmentContext<'a> {
- map: &'a InlineFragmentMap,
+ ranges: &'a Vec,
index: FragmentIndex,
}
impl<'a> InlineFragmentContext<'a> {
- pub fn new<'a>(map: &'a InlineFragmentMap, index: FragmentIndex) -> InlineFragmentContext<'a> {
+ pub fn new<'a>(ranges: &'a Vec, index: FragmentIndex) -> InlineFragmentContext<'a> {
InlineFragmentContext {
- map: map,
+ ranges: ranges,
index: index,
}
}
+ /// Iterates over all ranges that contain the fragment at context's index, outermost first.
+ #[inline(always)]
pub fn ranges(&self) -> RangeIterator<'a> {
- self.map.ranges_for_index(self.index)
+ RangeIterator {
+ iter: self.ranges.iter(),
+ index: self.index,
+ seen_first: false,
+ }
}
}
diff --git a/src/components/main/layout/text.rs b/src/components/main/layout/text.rs
index 44dd2251820..61f9dd655c9 100644
--- a/src/components/main/layout/text.rs
+++ b/src/components/main/layout/text.rs
@@ -6,7 +6,6 @@
use layout::flow::Flow;
use layout::fragment::{Fragment, ScannedTextFragment, ScannedTextFragmentInfo, UnscannedTextFragment};
-use layout::inline::InlineFragments;
use gfx::font::{FontMetrics, FontStyle};
use gfx::font_context::FontContext;
@@ -15,7 +14,6 @@ use gfx::text::text_run::TextRun;
use gfx::text::util::{CompressWhitespaceNewline, transform_text, CompressNone};
use servo_util::geometry::Au;
use servo_util::range::Range;
-use std::mem;
use style::ComputedValues;
use style::computed_values::{font_family, line_height, white_space};
use sync::Arc;
@@ -48,18 +46,15 @@ impl TextRunScanner {
debug!("TextRunScanner: scanning {:u} fragments for text runs...", inline.fragments.len());
}
- let InlineFragments {
- fragments: old_fragments,
- map: mut map
- } = mem::replace(&mut flow.as_inline().fragments, InlineFragments::new());
+ let fragments = &mut flow.as_inline().fragments;
let mut last_whitespace = true;
let mut new_fragments = Vec::new();
- for fragment_i in range(0, old_fragments.len()) {
+ for fragment_i in range(0, fragments.fragments.len()) {
debug!("TextRunScanner: considering fragment: {:u}", fragment_i);
- if fragment_i > 0 && !can_coalesce_text_nodes(old_fragments.as_slice(), fragment_i - 1, fragment_i) {
+ if fragment_i > 0 && !can_coalesce_text_nodes(fragments.fragments.as_slice(), fragment_i - 1, fragment_i) {
last_whitespace = self.flush_clump_to_list(font_context,
- old_fragments.as_slice(),
+ fragments.fragments.as_slice(),
&mut new_fragments,
last_whitespace);
}
@@ -70,19 +65,14 @@ impl TextRunScanner {
// Handle remaining clumps.
if self.clump.length() > CharIndex(0) {
drop(self.flush_clump_to_list(font_context,
- old_fragments.as_slice(),
+ fragments.fragments.as_slice(),
&mut new_fragments,
last_whitespace))
}
debug!("TextRunScanner: swapping out fragments.");
- // Swap out the old and new fragment list of the flow.
- map.fixup(old_fragments.as_slice(), new_fragments.as_slice());
- flow.as_inline().fragments = InlineFragments {
- fragments: new_fragments,
- map: map,
- }
+ fragments.fixup(new_fragments);
}
/// A "clump" is a range of inline flow leaves that can be merged together into a single