mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00: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
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue