mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
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 commit is contained in:
parent
5e4f132b3b
commit
3a451ff845
17 changed files with 427 additions and 104 deletions
|
@ -38,7 +38,7 @@ pub fn transform_text(text: &str,
|
||||||
output_text.push(ch);
|
output_text.push(ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
text.len() > 0 && is_in_whitespace(text.char_at_reverse(0), mode)
|
false
|
||||||
},
|
},
|
||||||
|
|
||||||
CompressionMode::CompressWhitespace | CompressionMode::CompressWhitespaceNewline => {
|
CompressionMode::CompressWhitespace | CompressionMode::CompressWhitespaceNewline => {
|
||||||
|
|
|
@ -48,7 +48,7 @@ use util;
|
||||||
use util::geometry::ZERO_POINT;
|
use util::geometry::ZERO_POINT;
|
||||||
use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
|
use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
|
||||||
use util::range::*;
|
use util::range::*;
|
||||||
use util::str::{is_whitespace, slice_chars};
|
use util::str::slice_chars;
|
||||||
use wrapper::{PseudoElementType, ThreadSafeLayoutNode};
|
use wrapper::{PseudoElementType, ThreadSafeLayoutNode};
|
||||||
|
|
||||||
/// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position
|
/// 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
|
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
|
/// Returns the text decoration of this fragment, according to the style of the nearest ancestor
|
||||||
/// element.
|
/// element.
|
||||||
///
|
///
|
||||||
|
@ -1275,10 +1305,9 @@ impl Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this element can be split. This is true for text fragments, unless
|
/// 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 {
|
pub fn can_split(&self) -> bool {
|
||||||
self.is_scanned_text_fragment() &&
|
self.is_scanned_text_fragment() && self.white_space_allow_wrap()
|
||||||
self.style.get_inheritedtext().white_space != white_space::T::pre
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if and only if this fragment is a generated content fragment.
|
/// Returns true if and only if this fragment is a generated content fragment.
|
||||||
|
@ -1352,9 +1381,10 @@ impl Fragment {
|
||||||
.metrics_for_range(range)
|
.metrics_for_range(range)
|
||||||
.advance_width;
|
.advance_width;
|
||||||
|
|
||||||
let min_line_inline_size = match self.style.get_inheritedtext().white_space {
|
let min_line_inline_size = if self.white_space_allow_wrap() {
|
||||||
white_space::T::pre | white_space::T::nowrap => max_line_inline_size,
|
text_fragment_info.run.min_width_for_range(range)
|
||||||
white_space::T::normal => text_fragment_info.run.min_width_for_range(range),
|
} else {
|
||||||
|
max_line_inline_size
|
||||||
};
|
};
|
||||||
|
|
||||||
result.union_block(&IntrinsicISizes {
|
result.union_block(&IntrinsicISizes {
|
||||||
|
@ -1533,7 +1563,6 @@ impl Fragment {
|
||||||
return None
|
return None
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut pieces_processed_count: u32 = 0;
|
|
||||||
let mut remaining_inline_size = max_inline_size;
|
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_start_range = Range::new(text_fragment_info.range.begin(), CharIndex(0));
|
||||||
let mut inline_end_range = None;
|
let mut inline_end_range = None;
|
||||||
|
@ -1560,18 +1589,9 @@ impl Fragment {
|
||||||
// Have we found the split point?
|
// Have we found the split point?
|
||||||
if advance <= remaining_inline_size || slice.glyphs.is_whitespace() {
|
if advance <= remaining_inline_size || slice.glyphs.is_whitespace() {
|
||||||
// Keep going; we haven't found the split point yet.
|
// 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");
|
debug!("calculate_split_position_using_breaking_strategy: enlarging span");
|
||||||
remaining_inline_size = remaining_inline_size - advance;
|
remaining_inline_size = remaining_inline_size - advance;
|
||||||
inline_start_range.extend_by(slice.range.length());
|
inline_start_range.extend_by(slice.range.length());
|
||||||
}
|
|
||||||
pieces_processed_count += 1;
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1668,21 +1688,6 @@ impl Fragment {
|
||||||
self.meld_with_next_inline_fragment(&next_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
|
/// Assigns replaced inline-size, padding, and margins for this fragment only if it is replaced
|
||||||
/// content per CSS 2.1 § 10.3.2.
|
/// content per CSS 2.1 § 10.3.2.
|
||||||
pub fn assign_replaced_inline_size_if_necessary(&mut self, container_inline_size: Au) {
|
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 {
|
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
|
return WhitespaceStrippingResult::RetainFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2306,7 +2311,7 @@ impl Fragment {
|
||||||
|
|
||||||
/// Returns true if the entire fragment was stripped.
|
/// Returns true if the entire fragment was stripped.
|
||||||
pub fn strip_trailing_whitespace_if_necessary(&mut self) -> WhitespaceStrippingResult {
|
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
|
return WhitespaceStrippingResult::RetainFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
|
|
||||||
use app_units::{Au, MAX_AU};
|
use app_units::Au;
|
||||||
use block::{AbsoluteAssignBSizesTraversal, AbsoluteStoreOverflowTraversal};
|
use block::{AbsoluteAssignBSizesTraversal, AbsoluteStoreOverflowTraversal};
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use display_list_builder::{FragmentDisplayListBuilding, InlineFlowDisplayListBuilding};
|
use display_list_builder::{FragmentDisplayListBuilding, InlineFlowDisplayListBuilding};
|
||||||
|
@ -179,15 +179,6 @@ int_range_index! {
|
||||||
struct FragmentIndex(isize)
|
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.
|
/// Arranges fragments into lines, splitting them up as necessary.
|
||||||
struct LineBreaker {
|
struct LineBreaker {
|
||||||
/// The floats we need to flow around.
|
/// The floats we need to flow around.
|
||||||
|
@ -321,17 +312,8 @@ impl LineBreaker {
|
||||||
Some(fragment) => fragment,
|
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.
|
// 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() {
|
if !self.pending_line_is_empty() {
|
||||||
|
@ -540,8 +522,7 @@ impl LineBreaker {
|
||||||
fn reflow_fragment(&mut self,
|
fn reflow_fragment(&mut self,
|
||||||
mut fragment: Fragment,
|
mut fragment: Fragment,
|
||||||
flow: &InlineFlow,
|
flow: &InlineFlow,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext) {
|
||||||
flags: InlineReflowFlags) {
|
|
||||||
// Determine initial placement for the fragment if we need to.
|
// Determine initial placement for the fragment if we need to.
|
||||||
//
|
//
|
||||||
// Also, determine whether we can legally break the line before, or inside, this fragment.
|
// 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;
|
self.pending_line.green_zone = line_bounds.size;
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
!flags.contains(NO_WRAP_INLINE_REFLOW_FLAG)
|
fragment.white_space_allow_wrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("LineBreaker: trying to append to line {} (fragment size: {:?}, green zone: {:?}): \
|
debug!("LineBreaker: trying to append to line {} (fragment size: {:?}, green zone: {:?}): \
|
||||||
|
@ -582,12 +563,14 @@ impl LineBreaker {
|
||||||
|
|
||||||
// If we must flush the line after finishing this fragment due to `white-space: pre`,
|
// If we must flush the line after finishing this fragment due to `white-space: pre`,
|
||||||
// detect that.
|
// detect that.
|
||||||
let line_flush_mode =
|
let line_flush_mode = if fragment.white_space_preserve_newlines() {
|
||||||
if flags.contains(WRAP_ON_NEWLINE_INLINE_REFLOW_FLAG) &&
|
if fragment.requires_line_break_afterward_if_wrapping_on_newlines() {
|
||||||
fragment.requires_line_break_afterward_if_wrapping_on_newlines() {
|
|
||||||
LineFlushMode::Flush
|
LineFlushMode::Flush
|
||||||
} else {
|
} else {
|
||||||
LineFlushMode::No
|
LineFlushMode::No
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LineFlushMode::No
|
||||||
};
|
};
|
||||||
|
|
||||||
// If we're not going to overflow the green zone vertically, we might still do so
|
// If we're not going to overflow the green zone vertically, we might still do so
|
||||||
|
@ -602,35 +585,23 @@ impl LineBreaker {
|
||||||
return
|
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
|
// If the wrapping mode prevents us from splitting, then back up and split at the last
|
||||||
// known good split point.
|
// known good split point.
|
||||||
if flags.contains(NO_WRAP_INLINE_REFLOW_FLAG) &&
|
if !fragment.white_space_allow_wrap() {
|
||||||
!flags.contains(WRAP_ON_NEWLINE_INLINE_REFLOW_FLAG) {
|
debug!("LineBreaker: fragment can't split; falling back to last known good split point");
|
||||||
debug!("LineBreaker: white-space: nowrap in effect; falling back to last known good \
|
|
||||||
split point");
|
|
||||||
if !self.split_line_at_last_known_good_position() {
|
if !self.split_line_at_last_known_good_position() {
|
||||||
// No line breaking opportunity exists at all for this line. Overflow.
|
// 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 {
|
} else {
|
||||||
self.work_list.push_front(fragment)
|
self.work_list.push_front(fragment);
|
||||||
}
|
}
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split it up!
|
// Split it up!
|
||||||
let available_inline_size = if !flags.contains(NO_WRAP_INLINE_REFLOW_FLAG) {
|
let available_inline_size = green_zone.inline -
|
||||||
green_zone.inline - self.pending_line.bounds.size.inline - indentation
|
self.pending_line.bounds.size.inline -
|
||||||
} else {
|
indentation;
|
||||||
MAX_AU
|
|
||||||
};
|
|
||||||
let inline_start_fragment;
|
let inline_start_fragment;
|
||||||
let inline_end_fragment;
|
let inline_end_fragment;
|
||||||
let split_result = match fragment.calculate_split_position(available_inline_size,
|
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();
|
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 => {
|
white_space::T::normal => {
|
||||||
// Flush the intrinsic sizes we were gathering up for the nonbroken run, if
|
// Flush the intrinsic sizes we were gathering up for the nonbroken run, if
|
||||||
// necessary.
|
// necessary.
|
||||||
|
@ -1378,7 +1370,7 @@ impl Flow for InlineFlow {
|
||||||
&intrinsic_sizes_for_nonbroken_run.finish());
|
&intrinsic_sizes_for_nonbroken_run.finish());
|
||||||
intrinsic_sizes_for_nonbroken_run = IntrinsicISizesContribution::new();
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,13 +40,10 @@ fn text(fragments: &LinkedList<Fragment>) -> String {
|
||||||
for fragment in fragments {
|
for fragment in fragments {
|
||||||
match fragment.specific {
|
match fragment.specific {
|
||||||
SpecificFragmentInfo::UnscannedText(ref info) => {
|
SpecificFragmentInfo::UnscannedText(ref info) => {
|
||||||
match fragment.white_space() {
|
if fragment.white_space_preserve_newlines() {
|
||||||
white_space::T::normal | white_space::T::nowrap => {
|
|
||||||
text.push_str(&info.text.replace("\n", " "));
|
|
||||||
}
|
|
||||||
white_space::T::pre => {
|
|
||||||
text.push_str(&info.text);
|
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();
|
let inherited_text_style = in_fragment.style().get_inheritedtext();
|
||||||
fontgroup = font_context.layout_font_group_for_style(font_style);
|
fontgroup = font_context.layout_font_group_for_style(font_style);
|
||||||
compression = match in_fragment.white_space() {
|
compression = match in_fragment.white_space() {
|
||||||
white_space::T::normal | white_space::T::nowrap => {
|
white_space::T::normal |
|
||||||
CompressionMode::CompressWhitespaceNewline
|
white_space::T::nowrap => CompressionMode::CompressWhitespaceNewline,
|
||||||
}
|
white_space::T::pre |
|
||||||
white_space::T::pre => CompressionMode::CompressNone,
|
white_space::T::pre_wrap => CompressionMode::CompressNone,
|
||||||
|
white_space::T::pre_line => CompressionMode::CompressWhitespace,
|
||||||
};
|
};
|
||||||
text_transform = inherited_text_style.text_transform;
|
text_transform = inherited_text_style.text_transform;
|
||||||
letter_spacing = inherited_text_style.letter_spacing.0;
|
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 string_before;
|
||||||
let insertion_point_before;
|
let insertion_point_before;
|
||||||
{
|
{
|
||||||
|
if !first_fragment.white_space_preserve_newlines() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let unscanned_text_fragment_info = match first_fragment.specific {
|
let unscanned_text_fragment_info = match first_fragment.specific {
|
||||||
SpecificFragmentInfo::UnscannedText(ref mut unscanned_text_fragment_info) => {
|
SpecificFragmentInfo::UnscannedText(ref mut unscanned_text_fragment_info) => {
|
||||||
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,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
if first_fragment.style.get_inheritedtext().white_space != white_space::T::pre {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let position = match unscanned_text_fragment_info.text.find('\n') {
|
let position = match unscanned_text_fragment_info.text.find('\n') {
|
||||||
Some(position) if position < unscanned_text_fragment_info.text.len() - 1 => {
|
Some(position) if position < unscanned_text_fragment_info.text.len() - 1 => {
|
||||||
position
|
position
|
||||||
|
|
|
@ -804,8 +804,11 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
|
||||||
// If you implement other values for this property, you will almost certainly
|
// If you implement other values for this property, you will almost certainly
|
||||||
// want to update this check.
|
// want to update this check.
|
||||||
match self.style().get_inheritedtext().white_space {
|
match self.style().get_inheritedtext().white_space {
|
||||||
white_space::T::normal => true,
|
white_space::T::normal |
|
||||||
_ => false,
|
white_space::T::nowrap => true,
|
||||||
|
white_space::T::pre |
|
||||||
|
white_space::T::pre_wrap |
|
||||||
|
white_space::T::pre_line => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2347,7 +2347,7 @@ pub mod longhands {
|
||||||
}
|
}
|
||||||
</%self:longhand>
|
</%self:longhand>
|
||||||
|
|
||||||
${single_keyword("white-space", "normal pre nowrap")}
|
${single_keyword("white-space", "normal pre nowrap pre-wrap pre-line")}
|
||||||
|
|
||||||
// TODO(pcwalton): `full-width`
|
// TODO(pcwalton): `full-width`
|
||||||
${single_keyword("text-transform", "none capitalize uppercase lowercase")}
|
${single_keyword("text-transform", "none capitalize uppercase lowercase")}
|
||||||
|
|
|
@ -3047,6 +3047,54 @@
|
||||||
"url": "/_mozilla/css/visibility_hidden.html"
|
"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": [
|
"css/whitespace_nowrap_a.html": [
|
||||||
{
|
{
|
||||||
"path": "css/whitespace_nowrap_a.html",
|
"path": "css/whitespace_nowrap_a.html",
|
||||||
|
@ -6888,6 +6936,54 @@
|
||||||
"url": "/_mozilla/css/visibility_hidden.html"
|
"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": [
|
"css/whitespace_nowrap_a.html": [
|
||||||
{
|
{
|
||||||
"path": "css/whitespace_nowrap_a.html",
|
"path": "css/whitespace_nowrap_a.html",
|
||||||
|
|
BIN
tests/wpt/mozilla/tests/css/swatch-lime.png
Normal file
BIN
tests/wpt/mozilla/tests/css/swatch-lime.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 84 B |
BIN
tests/wpt/mozilla/tests/css/swatch-orange.png
Normal file
BIN
tests/wpt/mozilla/tests/css/swatch-orange.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 84 B |
42
tests/wpt/mozilla/tests/css/white-space-mixed-002-ref.htm
Normal file
42
tests/wpt/mozilla/tests/css/white-space-mixed-002-ref.htm
Normal file
|
@ -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>
|
28
tests/wpt/mozilla/tests/css/white-space-mixed-002.htm
Normal file
28
tests/wpt/mozilla/tests/css/white-space-mixed-002.htm
Normal file
|
@ -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>
|
41
tests/wpt/mozilla/tests/css/white-space-normal-001-ref.htm
Normal file
41
tests/wpt/mozilla/tests/css/white-space-normal-001-ref.htm
Normal file
|
@ -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>
|
50
tests/wpt/mozilla/tests/css/white-space-normal-001.htm
Normal file
50
tests/wpt/mozilla/tests/css/white-space-normal-001.htm
Normal file
|
@ -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>
|
16
tests/wpt/mozilla/tests/css/white-space-pre-line-ref.htm
Normal file
16
tests/wpt/mozilla/tests/css/white-space-pre-line-ref.htm
Normal file
|
@ -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>
|
15
tests/wpt/mozilla/tests/css/white-space-pre-line.htm
Normal file
15
tests/wpt/mozilla/tests/css/white-space-pre-line.htm
Normal file
|
@ -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>
|
19
tests/wpt/mozilla/tests/css/white-space-pre-wrap-ref.htm
Normal file
19
tests/wpt/mozilla/tests/css/white-space-pre-wrap-ref.htm
Normal file
|
@ -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>
|
||||||
|
XX<br>
|
||||||
|
XX<br>
|
||||||
|
XX<br>
|
||||||
|
X X<br>
|
||||||
|
X<br>
|
||||||
|
X<br>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
18
tests/wpt/mozilla/tests/css/white-space-pre-wrap.htm
Normal file
18
tests/wpt/mozilla/tests/css/white-space-pre-wrap.htm
Normal file
|
@ -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>
|
Loading…
Add table
Add a link
Reference in a new issue