aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/inline.rs
diff options
context:
space:
mode:
authorClark Gaebel <cgaebel@mozilla.com>2014-10-13 12:20:56 -0700
committerClark Gaebel <cgaebel@mozilla.com>2014-10-15 16:04:21 -0700
commit481adcd6547bc26a9a019ddfda9effc15f0d5b07 (patch)
tree950c708cb0c8efb2c1303d523096a445af72ceb2 /components/layout/inline.rs
parent6a11ee89de82abae9d6607a6c2890692df5259eb (diff)
downloadservo-481adcd6547bc26a9a019ddfda9effc15f0d5b07.tar.gz
servo-481adcd6547bc26a9a019ddfda9effc15f0d5b07.zip
Fix whitespace_pre with incremental reflow turned on.
This implements fragment merging, in order to incrementally reflow linebroken text. This makes the `whitespace_pre.html` reftest pass with incremental reflow turned on with `-i`.
Diffstat (limited to 'components/layout/inline.rs')
-rw-r--r--components/layout/inline.rs105
1 files changed, 93 insertions, 12 deletions
diff --git a/components/layout/inline.rs b/components/layout/inline.rs
index 1e7e202689c..70b7ffa7d3e 100644
--- a/components/layout/inline.rs
+++ b/components/layout/inline.rs
@@ -11,6 +11,7 @@ use flow::{BaseFlow, FlowClass, Flow, InlineFlowClass, MutableFlowUtils};
use flow;
use fragment::{Fragment, InlineAbsoluteHypotheticalFragment, InlineBlockFragment};
use fragment::{ScannedTextFragment, ScannedTextFragmentInfo, SplitInfo};
+use incremental::RestyleDamage;
use layout_debug;
use model::IntrinsicISizesContribution;
use text;
@@ -25,6 +26,7 @@ use gfx::text::glyph::CharIndex;
use servo_util::geometry::Au;
use servo_util::logical_geometry::{LogicalRect, LogicalSize};
use servo_util::range::{IntRangeIndex, Range, RangeIndex};
+use servo_util::arc_ptr_eq;
use std::cmp::max;
use std::fmt;
use std::mem;
@@ -63,7 +65,7 @@ static FONT_SUPERSCRIPT_OFFSET_RATIO: f64 = 0.34;
/// with a float or a horizontal wall of the containing block. The block-start
/// inline-start corner of the green zone is the same as that of the line, but
/// the green zone can be taller and wider than the line itself.
-#[deriving(Encodable)]
+#[deriving(Encodable, Show)]
pub struct Line {
/// A range of line indices that describe line breaks.
///
@@ -217,6 +219,7 @@ impl LineBreaker {
{
// Enter a new scope so that `old_fragment_iter`'s borrow is released.
+ debug!("Scanning for lines. {} fragments.", old_fragments.len());
let mut old_fragment_iter = old_fragments.fragments.iter();
loop {
// acquire the next fragment to lay out from work list or fragment list
@@ -404,15 +407,15 @@ impl LineBreaker {
let split_fragment = |split: SplitInfo| {
let info = ScannedTextFragmentInfo::new(run.clone(), split.range);
let specific = ScannedTextFragment(info);
- let size = LogicalSize::new(writing_mode,
- split.inline_size,
- in_fragment.border_box.size.block);
+ let size = LogicalSize::new(
+ writing_mode, split.inline_size, in_fragment.border_box.size.block);
in_fragment.transform(size, specific)
};
debug!("LineBreaker: Pushing the fragment to the inline_start of the new-line character \
to the line.");
let mut inline_start = split_fragment(inline_start);
+ inline_start.save_new_line_pos();
inline_start.new_line_pos = vec![];
self.push_fragment_to_line(inline_start);
@@ -605,19 +608,21 @@ impl InlineFragments {
}
/// Strips ignorable whitespace from the start of a list of fragments.
- pub fn strip_ignorable_whitespace_from_start(&mut self) {
- // Fast path.
- if self.is_empty() {
- return
- }
+ ///
+ /// Returns some damage that must be added to the `InlineFlow`.
+ pub fn strip_ignorable_whitespace_from_start(&mut self) -> RestyleDamage {
+ if self.is_empty() { return RestyleDamage::empty() } // Fast path
// FIXME (rust#16151): This can be reverted back to using skip_while once
// the upstream bug is fixed.
let mut fragments = mem::replace(&mut self.fragments, vec![]).into_iter();
let mut new_fragments = Vec::new();
let mut skipping = true;
+ let mut damage = RestyleDamage::empty();
+
for fragment in fragments {
if skipping && fragment.is_ignorable_whitespace() {
+ damage = RestyleDamage::all();
debug!("stripping ignorable whitespace from start");
continue
}
@@ -627,24 +632,82 @@ impl InlineFragments {
}
self.fragments = new_fragments;
+ damage
}
/// Strips ignorable whitespace from the end of a list of fragments.
- pub fn strip_ignorable_whitespace_from_end(&mut self) {
- // Fast path.
+ ///
+ /// Returns some damage that must be added to the `InlineFlow`.
+ pub fn strip_ignorable_whitespace_from_end(&mut self) -> RestyleDamage {
if self.is_empty() {
- return
+ return RestyleDamage::empty();
}
+ let mut damage = RestyleDamage::empty();
+
let mut new_fragments = self.fragments.clone();
while new_fragments.len() > 0 &&
new_fragments.as_slice().last().as_ref().unwrap().is_ignorable_whitespace() {
debug!("stripping ignorable whitespace from end");
+ damage = RestyleDamage::all();
drop(new_fragments.pop());
}
self.fragments = new_fragments;
+ damage
+ }
+
+ /// This function merges previously-line-broken fragments back into their
+ /// original, pre-line-breaking form.
+ pub fn merge_broken_lines(&mut self) {
+ let mut work: RingBuf<Fragment> =
+ mem::replace(&mut self.fragments, Vec::new()).into_iter().collect();
+
+ let mut out: Vec<Fragment> = Vec::new();
+
+ loop {
+ let mut left: Fragment =
+ match work.pop_front() {
+ None => break,
+ Some(work) => work,
+ };
+
+ let right: Fragment =
+ match work.pop_front() {
+ None => {
+ out.push(left);
+ break;
+ }
+ Some(work) => work,
+ };
+
+ left.restore_new_line_pos();
+
+ let right_is_from_same_fragment =
+ match (&mut left.specific, &right.specific) {
+ (&ScannedTextFragment(ref mut left_info),
+ &ScannedTextFragment(ref right_info)) => {
+ if arc_ptr_eq(&left_info.run, &right_info.run)
+ && left_info.range.end() + CharIndex(1) == right_info.range.begin() {
+ left_info.range.extend_by(right_info.range.length() + CharIndex(1));
+ true
+ } else {
+ false
+ }
+ }
+ _ => false,
+ };
+
+ if right_is_from_same_fragment {
+ work.push_front(left);
+ } else {
+ out.push(left);
+ work.push_front(right);
+ }
+ }
+
+ mem::replace(&mut self.fragments, out);
}
}
@@ -898,6 +961,16 @@ impl InlineFlow {
(block_size_above_baseline, depth_below_baseline)
}
+
+ fn update_restyle_damage(&mut self) {
+ let mut damage = self.base.restyle_damage;
+
+ for frag in self.fragments.fragments.iter() {
+ damage.insert(frag.restyle_damage());
+ }
+
+ self.base.restyle_damage = damage;
+ }
}
impl Flow for InlineFlow {
@@ -914,6 +987,8 @@ impl Flow for InlineFlow {
}
fn bubble_inline_sizes(&mut self) {
+ self.update_restyle_damage();
+
let _scope = layout_debug_scope!("inline::bubble_inline_sizes {:s}", self.base.debug_id());
let writing_mode = self.base.writing_mode;
@@ -989,6 +1064,12 @@ impl Flow for InlineFlow {
containing_block_block_size);
}
+ debug!("lines: {}", self.lines);
+
+ self.fragments.merge_broken_lines();
+
+ self.lines = Vec::new();
+
let scanner_floats = self.base.floats.clone();
let mut scanner = LineBreaker::new(scanner_floats);
scanner.scan_for_lines(self, layout_context);