mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Simplify control flow of whitespace handling.
This commit is contained in:
parent
d8b4dab4e3
commit
260347e5dc
3 changed files with 100 additions and 72 deletions
|
@ -294,78 +294,96 @@ where
|
|||
}
|
||||
|
||||
fn handle_text(&mut self, info: &NodeAndStyleInfo<Node>, input: Cow<'dom, str>) {
|
||||
// Skip any leading whitespace as dictated by the node's style.
|
||||
let white_space = info.style.get_inherited_text().white_space;
|
||||
let (leading_whitespace, mut input) = self.handle_leading_whitespace(&input, white_space);
|
||||
if leading_whitespace || !input.is_empty() {
|
||||
// This text node should be pushed either to the next ongoing
|
||||
// inline level box with the parent style of that inline level box
|
||||
// that will be ended, or directly to the ongoing inline formatting
|
||||
// context with the parent style of that builder.
|
||||
let inlines = self.current_inline_level_boxes();
|
||||
let (preserved_leading_whitespace, mut input) =
|
||||
self.handle_leading_whitespace(&input, white_space);
|
||||
|
||||
let mut new_text_run_contents;
|
||||
let output;
|
||||
if !preserved_leading_whitespace && input.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
let mut last_box = inlines.last_mut().map(|last| last.borrow_mut());
|
||||
let last_text = last_box.as_mut().and_then(|last| match &mut **last {
|
||||
InlineLevelBox::TextRun(last) => Some(&mut last.text),
|
||||
_ => None,
|
||||
});
|
||||
// This text node should be pushed either to the next ongoing
|
||||
// inline level box with the parent style of that inline level box
|
||||
// that will be ended, or directly to the ongoing inline formatting
|
||||
// context with the parent style of that builder.
|
||||
let inlines = self.current_inline_level_boxes();
|
||||
|
||||
if let Some(text) = last_text {
|
||||
// Append to the existing text run
|
||||
new_text_run_contents = None;
|
||||
output = text;
|
||||
} else {
|
||||
new_text_run_contents = Some(String::new());
|
||||
output = new_text_run_contents.as_mut().unwrap();
|
||||
}
|
||||
let mut new_text_run_contents;
|
||||
let output;
|
||||
|
||||
if leading_whitespace {
|
||||
output.push(' ')
|
||||
}
|
||||
{
|
||||
let mut last_box = inlines.last_mut().map(|last| last.borrow_mut());
|
||||
let last_text = last_box.as_mut().and_then(|last| match &mut **last {
|
||||
InlineLevelBox::TextRun(last) => Some(&mut last.text),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
match (
|
||||
white_space.preserve_spaces(),
|
||||
white_space.preserve_newlines(),
|
||||
) {
|
||||
(true, true) => {
|
||||
output.push_str(input);
|
||||
},
|
||||
if let Some(text) = last_text {
|
||||
// Append to the existing text run
|
||||
new_text_run_contents = None;
|
||||
output = text;
|
||||
} else {
|
||||
new_text_run_contents = Some(String::new());
|
||||
output = new_text_run_contents.as_mut().unwrap();
|
||||
}
|
||||
|
||||
(true, false) => unreachable!(),
|
||||
if preserved_leading_whitespace {
|
||||
output.push(' ')
|
||||
}
|
||||
|
||||
(false, preserve_newlines) => loop {
|
||||
if let Some(i) = input.bytes().position(|b| {
|
||||
b.is_ascii_whitespace() && (!preserve_newlines || b != b'\n')
|
||||
match (
|
||||
white_space.preserve_spaces(),
|
||||
white_space.preserve_newlines(),
|
||||
) {
|
||||
// All whitespace is significant, so we don't need to transform
|
||||
// the input at all.
|
||||
(true, true) => {
|
||||
output.push_str(input);
|
||||
},
|
||||
|
||||
// There are no cases in CSS where where need to preserve spaces
|
||||
// but not newlines.
|
||||
(true, false) => unreachable!(),
|
||||
|
||||
// Spaces are not significant, but newlines might be. We need
|
||||
// to collapse non-significant whitespace as appropriate.
|
||||
(false, preserve_newlines) => loop {
|
||||
// If there are any spaces that need preserving, split the string
|
||||
// that precedes them, collapse them into a single whitespace,
|
||||
// then process the remainder of the string independently.
|
||||
if let Some(i) = input
|
||||
.bytes()
|
||||
.position(|b| b.is_ascii_whitespace() && (!preserve_newlines || b != b'\n'))
|
||||
{
|
||||
let (non_whitespace, rest) = input.split_at(i);
|
||||
output.push_str(non_whitespace);
|
||||
output.push(' ');
|
||||
|
||||
// Find the first byte that is either significant whitespace or
|
||||
// non-whitespace to continue processing it.
|
||||
if let Some(i) = rest.bytes().position(|b| {
|
||||
!b.is_ascii_whitespace() || (preserve_newlines && b == b'\n')
|
||||
}) {
|
||||
let (non_whitespace, rest) = input.split_at(i);
|
||||
output.push_str(non_whitespace);
|
||||
output.push(' ');
|
||||
|
||||
if let Some(i) = rest.bytes().position(|b| {
|
||||
!b.is_ascii_whitespace() || (preserve_newlines && b == b'\n')
|
||||
}) {
|
||||
input = &rest[i..];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
input = &rest[i..];
|
||||
} else {
|
||||
output.push_str(input);
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
} else {
|
||||
// No whitespace found, so no transformation is required.
|
||||
output.push_str(input);
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(text) = new_text_run_contents {
|
||||
inlines.push(ArcRefCell::new(InlineLevelBox::TextRun(TextRun {
|
||||
tag: Tag::from_node_and_style_info(info),
|
||||
parent_style: Arc::clone(&info.style),
|
||||
text,
|
||||
})))
|
||||
}
|
||||
if let Some(text) = new_text_run_contents {
|
||||
inlines.push(ArcRefCell::new(InlineLevelBox::TextRun(TextRun {
|
||||
tag: Tag::from_node_and_style_info(info),
|
||||
parent_style: Arc::clone(&info.style),
|
||||
text,
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue