diff options
author | Patrick Walton <pcwalton@mimiga.net> | 2015-08-05 09:28:39 -0700 |
---|---|---|
committer | Patrick Walton <pcwalton@mimiga.net> | 2015-08-11 11:42:20 -0700 |
commit | ae378a8c3e1b77fe4e1ab3b8602900d32844756c (patch) | |
tree | 0873c035bdd1684dde96ff5f6da8078fa58db541 /components/layout/construct.rs | |
parent | 9c528c6382ee4355f42824a7caad217c4eb8a3b0 (diff) | |
download | servo-ae378a8c3e1b77fe4e1ab3b8602900d32844756c.tar.gz servo-ae378a8c3e1b77fe4e1ab3b8602900d32844756c.zip |
layout: Rewrite whitespace stripping.
This patch makes Servo unconditionally strip whitespace before text run
scanning (assuming that the `white-space` property allows it). Whitespace
stripping during reflow is now only used for handling whitespace at the ends of
lines; reflow now never attempts to handle ignorable whitespace.
Many CSS tests pass now. There are some new failures, however.
The following reference tests now fail due to a pre-existing bug whereby
whitespace is used to calculate the position of inline hypothetical boxes for
elements with `display: inline; position: absolute`:
* `absolute-replaced-height-036.htm`
* `vertical-align-sub-001.htm`
* `vertical-align-super-001.htm`
The following reference tests fail due to a pre-existing bug whereby we don't
handle `font-size: 0` properly in inline reflow:
* `font-size-zero-1.htm`
* `font-size-zero-2.htm`
The following reference test fails due to the fact that it relied on our
incorrect insertion of whitespace to make room for the black background:
* `inline-formatting-context-007.htm`
Diffstat (limited to 'components/layout/construct.rs')
-rw-r--r-- | components/layout/construct.rs | 79 |
1 files changed, 35 insertions, 44 deletions
diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 7194281e628..ce4417a5a00 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -26,6 +26,7 @@ use fragment::{Fragment, GeneratedContentInfo, IframeFragmentInfo}; use fragment::{CanvasFragmentInfo, ImageFragmentInfo, InlineAbsoluteFragmentInfo}; use fragment::{InlineAbsoluteHypotheticalFragmentInfo, TableColumnFragmentInfo}; use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo}; +use fragment::{WhitespaceStrippingResult}; use incremental::{RECONSTRUCT_FLOW, RestyleDamage}; use inline::{InlineFlow, InlineFragmentNodeInfo}; use list_item::{ListItemFlow, ListStyleTypeContent}; @@ -58,6 +59,7 @@ use style::computed_values::{caption_side, display, empty_cells, float, list_sty use style::computed_values::{position}; use style::properties::{self, ComputedValues}; use url::Url; +use util::linked_list; use util::opts; /// The results of flow construction for a DOM node. @@ -266,12 +268,6 @@ impl InlineFragmentsAccumulator { } } -enum WhitespaceStrippingMode { - None, - FromStart, - FromEnd, -} - /// An object that knows how to create flows. pub struct FlowConstructor<'a> { /// The layout context. @@ -414,27 +410,16 @@ impl<'a> FlowConstructor<'a> { fragment_accumulator: InlineFragmentsAccumulator, flow: &mut FlowRef, flow_list: &mut Vec<FlowRef>, - whitespace_stripping: WhitespaceStrippingMode, node: &ThreadSafeLayoutNode) { let mut fragments = fragment_accumulator.to_intermediate_inline_fragments(); if fragments.is_empty() { return }; - match whitespace_stripping { - WhitespaceStrippingMode::None => {} - WhitespaceStrippingMode::FromStart => { - strip_ignorable_whitespace_from_start(&mut fragments.fragments); - if fragments.is_empty() { - return - }; - } - WhitespaceStrippingMode::FromEnd => { - strip_ignorable_whitespace_from_end(&mut fragments.fragments); - if fragments.is_empty() { - return - }; - } + strip_ignorable_whitespace_from_start(&mut fragments.fragments); + strip_ignorable_whitespace_from_end(&mut fragments.fragments); + if fragments.is_empty() { + return } // Build a list of all the inline-block fragments before fragments is moved. @@ -504,8 +489,7 @@ impl<'a> FlowConstructor<'a> { node: &ThreadSafeLayoutNode, kid: ThreadSafeLayoutNode, inline_fragment_accumulator: &mut InlineFragmentsAccumulator, - abs_descendants: &mut Descendants, - first_fragment: &mut bool) { + abs_descendants: &mut Descendants) { match kid.swap_out_construction_result() { ConstructionResult::None => {} ConstructionResult::Flow(mut kid_flow, kid_abs_descendants) => { @@ -527,7 +511,6 @@ impl<'a> FlowConstructor<'a> { InlineFragmentsAccumulator::new()), flow, consecutive_siblings, - WhitespaceStrippingMode::FromStart, node); if !consecutive_siblings.is_empty() { let consecutive_siblings = mem::replace(consecutive_siblings, vec!()); @@ -554,15 +537,6 @@ impl<'a> FlowConstructor<'a> { } = split; inline_fragment_accumulator.push_all(predecessors); - // If this is the first fragment in flow, then strip ignorable - // whitespace per CSS 2.1 § 9.2.1.1. - let whitespace_stripping = if *first_fragment { - *first_fragment = false; - WhitespaceStrippingMode::FromStart - } else { - WhitespaceStrippingMode::None - }; - // Flush any inline fragments that we were gathering up. debug!("flushing {} inline box(es) to flow A", inline_fragment_accumulator.fragments.fragments.len()); @@ -571,7 +545,6 @@ impl<'a> FlowConstructor<'a> { InlineFragmentsAccumulator::new()), flow, consecutive_siblings, - whitespace_stripping, node); // Push the flow generated by the {ib} split onto our list of @@ -625,7 +598,6 @@ impl<'a> FlowConstructor<'a> { let mut consecutive_siblings = vec!(); inline_fragment_accumulator.fragments.push_all(initial_fragments); - let mut first_fragment = inline_fragment_accumulator.fragments.is_empty(); // List of absolute descendants, in tree order. let mut abs_descendants = Descendants::new(); @@ -640,8 +612,7 @@ impl<'a> FlowConstructor<'a> { node, kid, &mut inline_fragment_accumulator, - &mut abs_descendants, - &mut first_fragment); + &mut abs_descendants); } // Perform a final flush of any inline fragments that we were gathering up to handle {ib} @@ -649,7 +620,6 @@ impl<'a> FlowConstructor<'a> { self.flush_inline_fragments_to_flow_or_list(inline_fragment_accumulator, &mut flow, &mut consecutive_siblings, - WhitespaceStrippingMode::FromEnd, node); if !consecutive_siblings.is_empty() { self.generate_anonymous_missing_child(consecutive_siblings, &mut flow, node); @@ -1665,10 +1635,21 @@ pub fn strip_ignorable_whitespace_from_start(this: &mut LinkedList<Fragment>) { return // Fast path. } - while !this.is_empty() && this.front().as_ref().unwrap().is_ignorable_whitespace() { - debug!("stripping ignorable whitespace from start"); - drop(this.pop_front()); + let mut leading_fragments_consisting_of_solely_bidi_control_characters = LinkedList::new(); + while !this.is_empty() { + match this.front_mut().as_mut().unwrap().strip_leading_whitespace_if_necessary() { + WhitespaceStrippingResult::RetainFragment => break, + WhitespaceStrippingResult::FragmentContainedOnlyBidiControlCharacters => { + leading_fragments_consisting_of_solely_bidi_control_characters.push_back( + this.pop_front().unwrap()) + } + WhitespaceStrippingResult::FragmentContainedOnlyWhitespace => { + this.pop_front(); + } + } } + linked_list::prepend_from(this, + &mut leading_fragments_consisting_of_solely_bidi_control_characters) } /// Strips ignorable whitespace from the end of a list of fragments. @@ -1677,10 +1658,20 @@ pub fn strip_ignorable_whitespace_from_end(this: &mut LinkedList<Fragment>) { return } - while !this.is_empty() && this.back().as_ref().unwrap().is_ignorable_whitespace() { - debug!("stripping ignorable whitespace from end"); - drop(this.pop_back()); + let mut trailing_fragments_consisting_of_solely_bidi_control_characters = LinkedList::new(); + while !this.is_empty() { + match this.back_mut().as_mut().unwrap().strip_trailing_whitespace_if_necessary() { + WhitespaceStrippingResult::RetainFragment => break, + WhitespaceStrippingResult::FragmentContainedOnlyBidiControlCharacters => { + trailing_fragments_consisting_of_solely_bidi_control_characters.push_front( + this.pop_back().unwrap()) + } + WhitespaceStrippingResult::FragmentContainedOnlyWhitespace => { + this.pop_back(); + } + } } + this.append(&mut trailing_fragments_consisting_of_solely_bidi_control_characters); } /// If the 'unicode-bidi' property has a value other than 'normal', return the bidi control codes |