aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/construct.rs
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2015-08-05 09:28:39 -0700
committerPatrick Walton <pcwalton@mimiga.net>2015-08-11 11:42:20 -0700
commitae378a8c3e1b77fe4e1ab3b8602900d32844756c (patch)
tree0873c035bdd1684dde96ff5f6da8078fa58db541 /components/layout/construct.rs
parent9c528c6382ee4355f42824a7caad217c4eb8a3b0 (diff)
downloadservo-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.rs79
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