diff options
author | Josh Matthews <josh@joshmatthews.net> | 2020-07-24 14:57:11 -0400 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2020-07-27 20:06:55 -0400 |
commit | 260347e5dc287b7d47e29c97d08fa4abba3e8a75 (patch) | |
tree | 3dcc8fa9da2cd463711e19cb48156841eb0b0686 /components/layout_2020/flow/construct.rs | |
parent | d8b4dab4e38c2928f034248e158e8bf9b5ad60d6 (diff) | |
download | servo-260347e5dc287b7d47e29c97d08fa4abba3e8a75.tar.gz servo-260347e5dc287b7d47e29c97d08fa4abba3e8a75.zip |
Simplify control flow of whitespace handling.
Diffstat (limited to 'components/layout_2020/flow/construct.rs')
-rw-r--r-- | components/layout_2020/flow/construct.rs | 138 |
1 files changed, 78 insertions, 60 deletions
diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs index 73aa0c151b5..5cb1fe51e73 100644 --- a/components/layout_2020/flow/construct.rs +++ b/components/layout_2020/flow/construct.rs @@ -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 mut new_text_run_contents; - let output; - - { - 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, - }); + let (preserved_leading_whitespace, mut input) = + self.handle_leading_whitespace(&input, white_space); - 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(); - } + if !preserved_leading_whitespace && input.is_empty() { + return; + } - if leading_whitespace { - output.push(' ') - } + // 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(); - match ( - white_space.preserve_spaces(), - white_space.preserve_newlines(), - ) { - (true, true) => { - output.push_str(input); - }, + let mut new_text_run_contents; + let output; - (true, false) => unreachable!(), + { + 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, + }); + + 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(); + } + + 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, + }))) } } } |