aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <metajack+bors@gmail.com>2015-10-20 12:38:54 -0600
committerbors-servo <metajack+bors@gmail.com>2015-10-20 12:38:54 -0600
commitc3ab71109ee2ffcc31b40890f4c6739d8f5b1333 (patch)
tree52a8702c5b00cf4ecb9f7f68ed6b378c4d33b9e3
parent5e4f132b3b63ad0e18cccf186e8d90a5054406b0 (diff)
parent3a451ff84517f63faaf2d3439ee56748f162eb9f (diff)
downloadservo-c3ab71109ee2ffcc31b40890f4c6739d8f5b1333.tar.gz
servo-c3ab71109ee2ffcc31b40890f4c6739d8f5b1333.zip
Auto merge of #7951 - eefriedman:white-space, r=pcwalton
Add support for `pre-wrap` and `pre-line` values for `white-space`. This is mostly straightforward. I had to modify a couple of places which were accidentally discarding whitespace. Fixes #1513. This fixes some relevant tests from the CSS testsuite... but a lot of them are either manual, or don't pass because of unrelated issues. (For example, white-space-mixed-002 renders correctly, but white-space-mixed-002-ref doesn't because of a float bug.) I'd appreciate any suggestions for how to go about adding tests for this. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/7951) <!-- Reviewable:end -->
-rw-r--r--components/gfx/text/util.rs2
-rw-r--r--components/layout/fragment.rs79
-rw-r--r--components/layout/inline.rs88
-rw-r--r--components/layout/text.rs28
-rw-r--r--components/layout/wrapper.rs7
-rw-r--r--components/style/properties.mako.rs2
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json96
-rw-r--r--tests/wpt/mozilla/tests/css/swatch-lime.pngbin0 -> 84 bytes
-rw-r--r--tests/wpt/mozilla/tests/css/swatch-orange.pngbin0 -> 84 bytes
-rw-r--r--tests/wpt/mozilla/tests/css/white-space-mixed-002-ref.htm42
-rw-r--r--tests/wpt/mozilla/tests/css/white-space-mixed-002.htm28
-rw-r--r--tests/wpt/mozilla/tests/css/white-space-normal-001-ref.htm41
-rw-r--r--tests/wpt/mozilla/tests/css/white-space-normal-001.htm50
-rw-r--r--tests/wpt/mozilla/tests/css/white-space-pre-line-ref.htm16
-rw-r--r--tests/wpt/mozilla/tests/css/white-space-pre-line.htm15
-rw-r--r--tests/wpt/mozilla/tests/css/white-space-pre-wrap-ref.htm19
-rw-r--r--tests/wpt/mozilla/tests/css/white-space-pre-wrap.htm18
17 files changed, 427 insertions, 104 deletions
diff --git a/components/gfx/text/util.rs b/components/gfx/text/util.rs
index 855cb2d0dcd..6736b301d12 100644
--- a/components/gfx/text/util.rs
+++ b/components/gfx/text/util.rs
@@ -38,7 +38,7 @@ pub fn transform_text(text: &str,
output_text.push(ch);
}
}
- text.len() > 0 && is_in_whitespace(text.char_at_reverse(0), mode)
+ false
},
CompressionMode::CompressWhitespace | CompressionMode::CompressWhitespaceNewline => {
diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs
index 469cb0b6654..308532d9768 100644
--- a/components/layout/fragment.rs
+++ b/components/layout/fragment.rs
@@ -48,7 +48,7 @@ use util;
use util::geometry::ZERO_POINT;
use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
use util::range::*;
-use util::str::{is_whitespace, slice_chars};
+use util::str::slice_chars;
use wrapper::{PseudoElementType, ThreadSafeLayoutNode};
/// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position
@@ -1248,6 +1248,36 @@ impl Fragment {
self.style().get_inheritedtext().white_space
}
+ pub fn white_space_allow_wrap(&self) -> bool {
+ match self.white_space() {
+ white_space::T::nowrap |
+ white_space::T::pre => false,
+ white_space::T::normal |
+ white_space::T::pre_wrap |
+ white_space::T::pre_line => true,
+ }
+ }
+
+ pub fn white_space_preserve_newlines(&self) -> bool {
+ match self.white_space() {
+ white_space::T::normal |
+ white_space::T::nowrap => false,
+ white_space::T::pre |
+ white_space::T::pre_wrap |
+ white_space::T::pre_line => true,
+ }
+ }
+
+ pub fn white_space_preserve_spaces(&self) -> bool {
+ match self.white_space() {
+ white_space::T::normal |
+ white_space::T::nowrap |
+ white_space::T::pre_line => false,
+ white_space::T::pre |
+ white_space::T::pre_wrap => true,
+ }
+ }
+
/// Returns the text decoration of this fragment, according to the style of the nearest ancestor
/// element.
///
@@ -1275,10 +1305,9 @@ impl Fragment {
}
/// Returns true if this element can be split. This is true for text fragments, unless
- /// `white-space: pre` is set.
+ /// `white-space: pre` or `white-space: nowrap` is set.
pub fn can_split(&self) -> bool {
- self.is_scanned_text_fragment() &&
- self.style.get_inheritedtext().white_space != white_space::T::pre
+ self.is_scanned_text_fragment() && self.white_space_allow_wrap()
}
/// Returns true if and only if this fragment is a generated content fragment.
@@ -1352,9 +1381,10 @@ impl Fragment {
.metrics_for_range(range)
.advance_width;
- let min_line_inline_size = match self.style.get_inheritedtext().white_space {
- white_space::T::pre | white_space::T::nowrap => max_line_inline_size,
- white_space::T::normal => text_fragment_info.run.min_width_for_range(range),
+ let min_line_inline_size = if self.white_space_allow_wrap() {
+ text_fragment_info.run.min_width_for_range(range)
+ } else {
+ max_line_inline_size
};
result.union_block(&IntrinsicISizes {
@@ -1533,7 +1563,6 @@ impl Fragment {
return None
};
- let mut pieces_processed_count: u32 = 0;
let mut remaining_inline_size = max_inline_size;
let mut inline_start_range = Range::new(text_fragment_info.range.begin(), CharIndex(0));
let mut inline_end_range = None;
@@ -1560,18 +1589,9 @@ impl Fragment {
// Have we found the split point?
if advance <= remaining_inline_size || slice.glyphs.is_whitespace() {
// Keep going; we haven't found the split point yet.
- if flags.contains(STARTS_LINE) &&
- pieces_processed_count == 0 &&
- slice.glyphs.is_whitespace() {
- debug!("calculate_split_position_using_breaking_strategy: skipping \
- leading trimmable whitespace");
- inline_start_range.shift_by(slice.range.length());
- } else {
- debug!("calculate_split_position_using_breaking_strategy: enlarging span");
- remaining_inline_size = remaining_inline_size - advance;
- inline_start_range.extend_by(slice.range.length());
- }
- pieces_processed_count += 1;
+ debug!("calculate_split_position_using_breaking_strategy: enlarging span");
+ remaining_inline_size = remaining_inline_size - advance;
+ inline_start_range.extend_by(slice.range.length());
continue
}
@@ -1668,21 +1688,6 @@ impl Fragment {
self.meld_with_next_inline_fragment(&next_fragment);
}
- /// Returns true if this fragment is an unscanned text fragment that consists entirely of
- /// whitespace that should be stripped.
- pub fn is_ignorable_whitespace(&self) -> bool {
- match self.white_space() {
- white_space::T::pre => return false,
- white_space::T::normal | white_space::T::nowrap => {}
- }
- match self.specific {
- SpecificFragmentInfo::UnscannedText(ref text_fragment_info) => {
- is_whitespace(&text_fragment_info.text)
- }
- _ => false,
- }
- }
-
/// Assigns replaced inline-size, padding, and margins for this fragment only if it is replaced
/// content per CSS 2.1 § 10.3.2.
pub fn assign_replaced_inline_size_if_necessary(&mut self, container_inline_size: Au) {
@@ -2243,7 +2248,7 @@ impl Fragment {
}
pub fn strip_leading_whitespace_if_necessary(&mut self) -> WhitespaceStrippingResult {
- if self.style.get_inheritedtext().white_space == white_space::T::pre {
+ if self.white_space_preserve_spaces() {
return WhitespaceStrippingResult::RetainFragment
}
@@ -2306,7 +2311,7 @@ impl Fragment {
/// Returns true if the entire fragment was stripped.
pub fn strip_trailing_whitespace_if_necessary(&mut self) -> WhitespaceStrippingResult {
- if self.style.get_inheritedtext().white_space == white_space::T::pre {
+ if self.white_space_preserve_spaces() {
return WhitespaceStrippingResult::RetainFragment
}
diff --git a/components/layout/inline.rs b/components/layout/inline.rs
index 73c9fc32489..d6704405e1b 100644
--- a/components/layout/inline.rs
+++ b/components/layout/inline.rs
@@ -4,7 +4,7 @@
#![deny(unsafe_code)]
-use app_units::{Au, MAX_AU};
+use app_units::Au;
use block::{AbsoluteAssignBSizesTraversal, AbsoluteStoreOverflowTraversal};
use context::LayoutContext;
use display_list_builder::{FragmentDisplayListBuilding, InlineFlowDisplayListBuilding};
@@ -179,15 +179,6 @@ int_range_index! {
struct FragmentIndex(isize)
}
-bitflags! {
- flags InlineReflowFlags: u8 {
- #[doc = "The `white-space: nowrap` property from CSS 2.1 § 16.6 is in effect."]
- const NO_WRAP_INLINE_REFLOW_FLAG = 0x01,
- #[doc = "The `white-space: pre` property from CSS 2.1 § 16.6 is in effect."]
- const WRAP_ON_NEWLINE_INLINE_REFLOW_FLAG = 0x02
- }
-}
-
/// Arranges fragments into lines, splitting them up as necessary.
struct LineBreaker {
/// The floats we need to flow around.
@@ -321,17 +312,8 @@ impl LineBreaker {
Some(fragment) => fragment,
};
- // Set up our reflow flags.
- let flags = match fragment.style().get_inheritedtext().white_space {
- white_space::T::normal => InlineReflowFlags::empty(),
- white_space::T::nowrap => NO_WRAP_INLINE_REFLOW_FLAG,
- white_space::T::pre => {
- WRAP_ON_NEWLINE_INLINE_REFLOW_FLAG | NO_WRAP_INLINE_REFLOW_FLAG
- }
- };
-
// Try to append the fragment.
- self.reflow_fragment(fragment, flow, layout_context, flags);
+ self.reflow_fragment(fragment, flow, layout_context);
}
if !self.pending_line_is_empty() {
@@ -540,8 +522,7 @@ impl LineBreaker {
fn reflow_fragment(&mut self,
mut fragment: Fragment,
flow: &InlineFlow,
- layout_context: &LayoutContext,
- flags: InlineReflowFlags) {
+ layout_context: &LayoutContext) {
// Determine initial placement for the fragment if we need to.
//
// Also, determine whether we can legally break the line before, or inside, this fragment.
@@ -552,7 +533,7 @@ impl LineBreaker {
self.pending_line.green_zone = line_bounds.size;
false
} else {
- !flags.contains(NO_WRAP_INLINE_REFLOW_FLAG)
+ fragment.white_space_allow_wrap()
};
debug!("LineBreaker: trying to append to line {} (fragment size: {:?}, green zone: {:?}): \
@@ -582,13 +563,15 @@ impl LineBreaker {
// If we must flush the line after finishing this fragment due to `white-space: pre`,
// detect that.
- let line_flush_mode =
- if flags.contains(WRAP_ON_NEWLINE_INLINE_REFLOW_FLAG) &&
- fragment.requires_line_break_afterward_if_wrapping_on_newlines() {
+ let line_flush_mode = if fragment.white_space_preserve_newlines() {
+ if fragment.requires_line_break_afterward_if_wrapping_on_newlines() {
LineFlushMode::Flush
} else {
LineFlushMode::No
- };
+ }
+ } else {
+ LineFlushMode::No
+ };
// If we're not going to overflow the green zone vertically, we might still do so
// horizontally. We'll try to place the whole fragment on this line and break somewhere if
@@ -602,35 +585,23 @@ impl LineBreaker {
return
}
- // If we can't split the fragment and we're at the start of the line, then just overflow.
- if !fragment.can_split() && self.pending_line_is_empty() {
- debug!("LineBreaker: fragment can't split and line {} is empty, so overflowing",
- self.lines.len());
- self.push_fragment_to_line(layout_context, fragment, LineFlushMode::No);
- return
- }
-
// If the wrapping mode prevents us from splitting, then back up and split at the last
// known good split point.
- if flags.contains(NO_WRAP_INLINE_REFLOW_FLAG) &&
- !flags.contains(WRAP_ON_NEWLINE_INLINE_REFLOW_FLAG) {
- debug!("LineBreaker: white-space: nowrap in effect; falling back to last known good \
- split point");
+ if !fragment.white_space_allow_wrap() {
+ debug!("LineBreaker: fragment can't split; falling back to last known good split point");
if !self.split_line_at_last_known_good_position() {
// No line breaking opportunity exists at all for this line. Overflow.
- self.push_fragment_to_line(layout_context, fragment, LineFlushMode::No)
+ self.push_fragment_to_line(layout_context, fragment, line_flush_mode);
} else {
- self.work_list.push_front(fragment)
+ self.work_list.push_front(fragment);
}
- return
+ return;
}
// Split it up!
- let available_inline_size = if !flags.contains(NO_WRAP_INLINE_REFLOW_FLAG) {
- green_zone.inline - self.pending_line.bounds.size.inline - indentation
- } else {
- MAX_AU
- };
+ let available_inline_size = green_zone.inline -
+ self.pending_line.bounds.size.inline -
+ indentation;
let inline_start_fragment;
let inline_end_fragment;
let split_result = match fragment.calculate_split_position(available_inline_size,
@@ -1371,6 +1342,27 @@ impl Flow for InlineFlow {
intrinsic_sizes_for_inline_run = IntrinsicISizesContribution::new();
}
}
+ white_space::T::pre_wrap |
+ white_space::T::pre_line => {
+ // Flush the intrinsic sizes we were gathering up for the nonbroken run, if
+ // necessary.
+ intrinsic_sizes_for_inline_run.union_inline(
+ &intrinsic_sizes_for_nonbroken_run.finish());
+ intrinsic_sizes_for_nonbroken_run = IntrinsicISizesContribution::new();
+
+ intrinsic_sizes_for_nonbroken_run.union_inline(&intrinsic_sizes_for_fragment);
+
+ // Flush the intrinsic sizes we've been gathering up in order to handle the
+ // line break, if necessary.
+ if fragment.requires_line_break_afterward_if_wrapping_on_newlines() {
+ intrinsic_sizes_for_inline_run.union_inline(
+ &intrinsic_sizes_for_nonbroken_run.finish());
+ intrinsic_sizes_for_nonbroken_run = IntrinsicISizesContribution::new();
+ intrinsic_sizes_for_flow.union_block(
+ &intrinsic_sizes_for_inline_run.finish());
+ intrinsic_sizes_for_inline_run = IntrinsicISizesContribution::new();
+ }
+ }
white_space::T::normal => {
// Flush the intrinsic sizes we were gathering up for the nonbroken run, if
// necessary.
@@ -1378,7 +1370,7 @@ impl Flow for InlineFlow {
&intrinsic_sizes_for_nonbroken_run.finish());
intrinsic_sizes_for_nonbroken_run = IntrinsicISizesContribution::new();
- intrinsic_sizes_for_nonbroken_run.union_inline(&intrinsic_sizes_for_fragment)
+ intrinsic_sizes_for_nonbroken_run.union_inline(&intrinsic_sizes_for_fragment);
}
}
}
diff --git a/components/layout/text.rs b/components/layout/text.rs
index 6efc5302a61..e007eb3d25b 100644
--- a/components/layout/text.rs
+++ b/components/layout/text.rs
@@ -40,13 +40,10 @@ fn text(fragments: &LinkedList<Fragment>) -> String {
for fragment in fragments {
match fragment.specific {
SpecificFragmentInfo::UnscannedText(ref info) => {
- match fragment.white_space() {
- white_space::T::normal | white_space::T::nowrap => {
- text.push_str(&info.text.replace("\n", " "));
- }
- white_space::T::pre => {
- text.push_str(&info.text);
- }
+ if fragment.white_space_preserve_newlines() {
+ text.push_str(&info.text);
+ } else {
+ text.push_str(&info.text.replace("\n", " "));
}
}
_ => {}
@@ -161,10 +158,11 @@ impl TextRunScanner {
let inherited_text_style = in_fragment.style().get_inheritedtext();
fontgroup = font_context.layout_font_group_for_style(font_style);
compression = match in_fragment.white_space() {
- white_space::T::normal | white_space::T::nowrap => {
- CompressionMode::CompressWhitespaceNewline
- }
- white_space::T::pre => CompressionMode::CompressNone,
+ white_space::T::normal |
+ white_space::T::nowrap => CompressionMode::CompressWhitespaceNewline,
+ white_space::T::pre |
+ white_space::T::pre_wrap => CompressionMode::CompressNone,
+ white_space::T::pre_line => CompressionMode::CompressWhitespace,
};
text_transform = inherited_text_style.text_transform;
letter_spacing = inherited_text_style.letter_spacing.0;
@@ -413,6 +411,10 @@ fn split_first_fragment_at_newline_if_necessary(fragments: &mut LinkedList<Fragm
let string_before;
let insertion_point_before;
{
+ if !first_fragment.white_space_preserve_newlines() {
+ return;
+ }
+
let unscanned_text_fragment_info = match first_fragment.specific {
SpecificFragmentInfo::UnscannedText(ref mut unscanned_text_fragment_info) => {
unscanned_text_fragment_info
@@ -420,10 +422,6 @@ fn split_first_fragment_at_newline_if_necessary(fragments: &mut LinkedList<Fragm
_ => return,
};
- if first_fragment.style.get_inheritedtext().white_space != white_space::T::pre {
- return
- }
-
let position = match unscanned_text_fragment_info.text.find('\n') {
Some(position) if position < unscanned_text_fragment_info.text.len() - 1 => {
position
diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs
index 74d3a57b2fc..7c13cc6d97c 100644
--- a/components/layout/wrapper.rs
+++ b/components/layout/wrapper.rs
@@ -804,8 +804,11 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
// If you implement other values for this property, you will almost certainly
// want to update this check.
match self.style().get_inheritedtext().white_space {
- white_space::T::normal => true,
- _ => false,
+ white_space::T::normal |
+ white_space::T::nowrap => true,
+ white_space::T::pre |
+ white_space::T::pre_wrap |
+ white_space::T::pre_line => false,
}
}
}
diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs
index 1206a83069f..c8f1834b1ac 100644
--- a/components/style/properties.mako.rs
+++ b/components/style/properties.mako.rs
@@ -2347,7 +2347,7 @@ pub mod longhands {
}
</%self:longhand>
- ${single_keyword("white-space", "normal pre nowrap")}
+ ${single_keyword("white-space", "normal pre nowrap pre-wrap pre-line")}
// TODO(pcwalton): `full-width`
${single_keyword("text-transform", "none capitalize uppercase lowercase")}
diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json
index ba6d921e301..c966afa4caa 100644
--- a/tests/wpt/mozilla/meta/MANIFEST.json
+++ b/tests/wpt/mozilla/meta/MANIFEST.json
@@ -3047,6 +3047,54 @@
"url": "/_mozilla/css/visibility_hidden.html"
}
],
+ "css/white-space-mixed-002.htm": [
+ {
+ "path": "css/white-space-mixed-002.htm",
+ "references": [
+ [
+ "/_mozilla/css/white-space-mixed-002-ref.htm",
+ "=="
+ ]
+ ],
+ "url": "/_mozilla/css/white-space-mixed-002.htm"
+ }
+ ],
+ "css/white-space-normal-001.htm": [
+ {
+ "path": "css/white-space-normal-001.htm",
+ "references": [
+ [
+ "/_mozilla/css/white-space-normal-001-ref.htm",
+ "=="
+ ]
+ ],
+ "url": "/_mozilla/css/white-space-normal-001.htm"
+ }
+ ],
+ "css/white-space-pre-line.htm": [
+ {
+ "path": "css/white-space-pre-line.htm",
+ "references": [
+ [
+ "/_mozilla/css/white-space-pre-line-ref.htm",
+ "=="
+ ]
+ ],
+ "url": "/_mozilla/css/white-space-pre-line.htm"
+ }
+ ],
+ "css/white-space-pre-wrap.htm": [
+ {
+ "path": "css/white-space-pre-wrap.htm",
+ "references": [
+ [
+ "/_mozilla/css/white-space-pre-wrap-ref.htm",
+ "=="
+ ]
+ ],
+ "url": "/_mozilla/css/white-space-pre-wrap.htm"
+ }
+ ],
"css/whitespace_nowrap_a.html": [
{
"path": "css/whitespace_nowrap_a.html",
@@ -6888,6 +6936,54 @@
"url": "/_mozilla/css/visibility_hidden.html"
}
],
+ "css/white-space-mixed-002.htm": [
+ {
+ "path": "css/white-space-mixed-002.htm",
+ "references": [
+ [
+ "/_mozilla/css/white-space-mixed-002-ref.htm",
+ "=="
+ ]
+ ],
+ "url": "/_mozilla/css/white-space-mixed-002.htm"
+ }
+ ],
+ "css/white-space-normal-001.htm": [
+ {
+ "path": "css/white-space-normal-001.htm",
+ "references": [
+ [
+ "/_mozilla/css/white-space-normal-001-ref.htm",
+ "=="
+ ]
+ ],
+ "url": "/_mozilla/css/white-space-normal-001.htm"
+ }
+ ],
+ "css/white-space-pre-line.htm": [
+ {
+ "path": "css/white-space-pre-line.htm",
+ "references": [
+ [
+ "/_mozilla/css/white-space-pre-line-ref.htm",
+ "=="
+ ]
+ ],
+ "url": "/_mozilla/css/white-space-pre-line.htm"
+ }
+ ],
+ "css/white-space-pre-wrap.htm": [
+ {
+ "path": "css/white-space-pre-wrap.htm",
+ "references": [
+ [
+ "/_mozilla/css/white-space-pre-wrap-ref.htm",
+ "=="
+ ]
+ ],
+ "url": "/_mozilla/css/white-space-pre-wrap.htm"
+ }
+ ],
"css/whitespace_nowrap_a.html": [
{
"path": "css/whitespace_nowrap_a.html",
diff --git a/tests/wpt/mozilla/tests/css/swatch-lime.png b/tests/wpt/mozilla/tests/css/swatch-lime.png
new file mode 100644
index 00000000000..55fd7fdaedf
--- /dev/null
+++ b/tests/wpt/mozilla/tests/css/swatch-lime.png
Binary files differ
diff --git a/tests/wpt/mozilla/tests/css/swatch-orange.png b/tests/wpt/mozilla/tests/css/swatch-orange.png
new file mode 100644
index 00000000000..d3cd498b52b
--- /dev/null
+++ b/tests/wpt/mozilla/tests/css/swatch-orange.png
Binary files differ
diff --git a/tests/wpt/mozilla/tests/css/white-space-mixed-002-ref.htm b/tests/wpt/mozilla/tests/css/white-space-mixed-002-ref.htm
new file mode 100644
index 00000000000..15d0c4d1384
--- /dev/null
+++ b/tests/wpt/mozilla/tests/css/white-space-mixed-002-ref.htm
@@ -0,0 +1,42 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!-- This is a lightly modified copy of
+ tests/wpt/css-tests/css21_dev/html4/reference/white-space-mixed-002-ref.htm,
+ changed to work around a bug in Servo's float handling.
+-->
+<html>
+
+ <head>
+
+ <title>CSS Reftest Reference</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style type="text/css">
+ div
+ {
+ background-color: yellow;
+ border: blue solid medium;
+ margin-left: 20px;
+ width: 140px;
+ margin-top: 36px;
+ }
+ div+div { margin-top: 56px; }
+
+ img {vertical-align: top;}
+
+ img:first-child {float: right;}
+
+ </style>
+
+ </head>
+
+ <body>
+
+ <p>Test passes if the contents of the 2 blue stripes are <strong>identical</strong>.</p>
+
+ <div><img src="swatch-orange.png" width="20" height="20" alt="Image download support must be enabled"><img src="swatch-orange.png" width="20" height="20" alt="Image download support must be enabled"></div>
+
+ <div><img src="swatch-orange.png" width="20" height="20" alt="Image download support must be enabled"><img src="swatch-orange.png" width="20" height="20" alt="Image download support must be enabled"></div>
+
+ </body>
+</html>
diff --git a/tests/wpt/mozilla/tests/css/white-space-mixed-002.htm b/tests/wpt/mozilla/tests/css/white-space-mixed-002.htm
new file mode 100644
index 00000000000..2c27b84a680
--- /dev/null
+++ b/tests/wpt/mozilla/tests/css/white-space-mixed-002.htm
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!-- This is an exact copy of tests/wpt/css-tests/css21_dev/html4/white-space-mixed-002.htm;
+ the corresponding reference page is modified so Servo passes.
+-->
+<html>
+ <head>
+ <title>CSS Test: white-space: mixed tests (simple)</title>
+ <link rel="author" title="Ian Hickson" href="mailto:ian@hixie.ch">
+ <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> <!-- 2012-06-29 -->
+ <link rel="alternate" href="http://www.hixie.ch/tests/adhoc/css/text/white-space/mixed/002.html" type="text/html">
+ <link rel="help" href="http://www.w3.org/TR/CSS21/text.html#white-space-model">
+ <link rel="match" href="reference/white-space-mixed-002-ref.htm">
+
+ <meta name="flags" content="ahem">
+
+ <style type="text/css">
+ .test { border: solid blue; font: 1.25em/1 Ahem; background: yellow; color: orange; float: left; clear: left; margin: 1em; }
+ .normal { white-space: normal; }
+ .nowrap { white-space: nowrap; }
+ .pre { white-space: pre; }
+ </style>
+ </head>
+ <body>
+ <p>Test passes if the contents of the 2 blue stripes are <strong>identical</strong>.</p>
+ <div class="test normal">[<span class="normal"> </span><span class="pre"> </span><span class="normal"> </span><span class="pre"> </span><span class="normal"> </span>]</div>
+ <div class="test pre">[ ]</div>
+ </body>
+</html>
diff --git a/tests/wpt/mozilla/tests/css/white-space-normal-001-ref.htm b/tests/wpt/mozilla/tests/css/white-space-normal-001-ref.htm
new file mode 100644
index 00000000000..07d1680fe49
--- /dev/null
+++ b/tests/wpt/mozilla/tests/css/white-space-normal-001-ref.htm
@@ -0,0 +1,41 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!-- This is a lightly modified copy of
+ tests/wpt/css-tests/css21_dev/html4/reference/white-space-normal-001-ref.htm,
+ changed to work around a bug in Servo's margin handling (?).
+-->
+<html>
+
+ <head>
+
+ <title>CSS Reftest Reference</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style type="text/css">
+ div
+ {
+ background-color: green;
+ border: black solid medium;
+ height: 120px;
+ text-align: center;
+ width: 60px;
+ margin-top: 19px;
+ }
+
+ img
+ {
+ vertical-align: top;
+ }
+
+ </style>
+
+ </head>
+
+ <body>
+
+ <p>Test passes if there is a rectangle with 3 columns (1 dark green, 1 light green and then 1 dark green) and if there is <strong>no red</strong>.</p>
+
+ <div><img src="swatch-lime.png" width="20" height="120" alt="Image download support must be enabled"></div>
+
+ </body>
+</html>
diff --git a/tests/wpt/mozilla/tests/css/white-space-normal-001.htm b/tests/wpt/mozilla/tests/css/white-space-normal-001.htm
new file mode 100644
index 00000000000..d71aaf5976a
--- /dev/null
+++ b/tests/wpt/mozilla/tests/css/white-space-normal-001.htm
@@ -0,0 +1,50 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!-- This is an exact copy of tests/wpt/css-tests/css21_dev/html4/white-space-normal-001.htm;
+ the corresponding reference page is modified so Servo passes.
+-->
+<html>
+ <head>
+ <title>CSS Test: white-space normal: simple tests</title>
+ <link rel="author" title="Ian Hickson" href="mailto:ian@hixie.ch">
+ <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> <!-- 2012-06-29 -->
+ <link rel="alternate" href="http://www.hixie.ch/tests/adhoc/css/text/white-space/normal/001.html" type="text/html">
+ <link rel="help" href="http://www.w3.org/TR/CSS21/text.html#white-space-model">
+ <link rel="match" href="reference/white-space-normal-001-ref.htm">
+
+ <meta name="flags" content="ahem">
+
+ <style type="text/css">
+ * { white-space: normal; }
+ div { display: block; }
+ span { display: inline; }
+ table { padding: 0; border-spacing: 0; border: solid; }
+ td { font: 20px/1 Ahem; color: red; background: red; padding: 0; }
+ .red { background: red; }
+ .green { color: green; background: lime; }
+ .check { width: 3em; background: lime; color: green; }
+ </style>
+ </head>
+ <body>
+ <p>Test passes if there is a rectangle with 3 columns (1 dark green, 1 light green and then 1 dark green) and if there is <strong>no red</strong>.</p>
+ <table>
+ <tr>
+ <td>
+ <div class="red"> </div>
+ <div class="red"> <div></div></div>
+ <div class="red"> <div> </div></div>
+ <div class="red"><div> </div></div>
+ <div class="red"><div> </div> </div>
+ <div class="red"><div></div> </div>
+ <div class="red"> <div></div> </div>
+ <div class="red"> <div> </div> </div>
+ <div class="green"><span>X</span> <span>X</span></div>
+ <div class="green"> <span>X</span> <span>X</span></div>
+ <div class="green"><span>X</span> <span>X</span> </div>
+ <div class="green"> <div></div> <span>X</span> <span>X</span> </div>
+ <div class="green"> <span>X</span> <span>X</span> <div></div> </div>
+ <div class="check">X X</div>
+ </td>
+ </tr>
+ </table>
+ </body>
+</html>
diff --git a/tests/wpt/mozilla/tests/css/white-space-pre-line-ref.htm b/tests/wpt/mozilla/tests/css/white-space-pre-line-ref.htm
new file mode 100644
index 00000000000..631c37056b5
--- /dev/null
+++ b/tests/wpt/mozilla/tests/css/white-space-pre-line-ref.htm
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>whitespace pre-line basic functionality test</title>
+ <style>
+ div { white-space: normal; font: 1.25em/1 Ahem; width: 6em }
+ </style>
+ </head>
+ <body>
+<div>X<br>
+XX<br>
+XX XX<br>
+XX<br>
+</div>
+ </body>
+</html>
diff --git a/tests/wpt/mozilla/tests/css/white-space-pre-line.htm b/tests/wpt/mozilla/tests/css/white-space-pre-line.htm
new file mode 100644
index 00000000000..d9afec29d77
--- /dev/null
+++ b/tests/wpt/mozilla/tests/css/white-space-pre-line.htm
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>whitespace pre-line basic functionality test</title>
+ <style>
+ div { white-space: pre-line; font: 1.25em/1 Ahem; width: 6em }
+ </style>
+ </head>
+<body>
+<div>X<!--newline in pre-line-->
+ XX<!--whitespace at start of line-->
+XX XX XX<!-- wrapping -->
+</div>
+</body>
+</html>
diff --git a/tests/wpt/mozilla/tests/css/white-space-pre-wrap-ref.htm b/tests/wpt/mozilla/tests/css/white-space-pre-wrap-ref.htm
new file mode 100644
index 00000000000..f6bda4e0ee8
--- /dev/null
+++ b/tests/wpt/mozilla/tests/css/white-space-pre-wrap-ref.htm
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>whitespace pre-wrap basic functionality test</title>
+ <style>
+ div { white-space: normal; font: 1.25em/1 Ahem; width: 6em }
+ </style>
+ </head>
+ <body>
+<div>X<br>
+&nbsp;&nbsp;XX<br>
+&nbsp;&nbsp;XX<br>
+XX<br>
+X&nbsp;&nbsp;X<br>
+X<br>
+X<br>
+</div>
+ </body>
+</html>
diff --git a/tests/wpt/mozilla/tests/css/white-space-pre-wrap.htm b/tests/wpt/mozilla/tests/css/white-space-pre-wrap.htm
new file mode 100644
index 00000000000..22f61f31fab
--- /dev/null
+++ b/tests/wpt/mozilla/tests/css/white-space-pre-wrap.htm
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>whitespace pre-wrap basic functionality test</title>
+ <style>
+ div { white-space: pre-wrap; font: 1.25em/1 Ahem; width: 6em }
+ </style>
+ </head>
+<body>
+<div>X<!--newline in pre-wrap-->
+ XX<!--whitespace at start of line-->
+ XX XX<!--wrapping-->
+X X<!--whitespace in middle line-->
+X <!--trailing whitespace-->
+X
+</div>
+</body>
+</html>