Keep 1st collapsible space after a preserved one (#32037)

The logic was to remove any collapsible white space preceded by other
white space. However, this should only happen if the preceding space
is also collapsible.

Also fixing the logic in ContentSizesComputation, which was wrong
but previously it didn't matter.
This commit is contained in:
Oriol Brufau 2024-04-15 14:02:09 +02:00 committed by GitHub
parent 5083dc7d17
commit 1898394cb3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 19 additions and 17 deletions

View file

@ -2306,7 +2306,8 @@ struct ContentSizesComputation<'a> {
current_line: ContentSizes,
/// Size for whitepsace pending to be added to this line.
pending_whitespace: Au,
/// Whether or not this IFC has seen any content, excluding collapsed whitespace.
/// Whether or not the current line has seen any content (excluding collapsed whitespace),
/// when sizing under a max-content constraint.
had_content_yet: bool,
/// Stack of ending padding, margin, and border to add to the length
/// when an inline box finishes.
@ -2366,7 +2367,6 @@ impl<'a> ContentSizesComputation<'a> {
// If this run is a forced line break, we *must* break the line
// and start measuring from the inline origin once more.
if text_run.glyph_run_is_preserved_newline(run) {
self.had_content_yet = true;
self.forced_line_break();
self.current_line = ContentSizes::zero();
continue;
@ -2375,12 +2375,12 @@ impl<'a> ContentSizesComputation<'a> {
let white_space =
text_run.parent_style.get_inherited_text().white_space;
if !white_space.preserve_spaces() {
// Discard any leading whitespace in the IFC. This will always be trimmed.
// TODO: need to handle !white_space.allow_wrap().
self.line_break_opportunity();
// Discard any leading whitespace in the line. This will always be trimmed.
if self.had_content_yet {
// Wait to take into account other whitespace until we see more content.
// Whitespace at the end of the IFC will always be trimmed.
// TODO: need to handle !white_space.allow_wrap().
self.line_break_opportunity();
// Whitespace at the end of the line will always be trimmed.
self.pending_whitespace += advance;
}
continue;
@ -2433,6 +2433,7 @@ impl<'a> ContentSizesComputation<'a> {
self.paragraph.max_content =
std::cmp::max(self.paragraph.max_content, self.current_line.max_content);
self.current_line.max_content = Au::zero();
self.had_content_yet = false;
}
fn commit_pending_whitespace(&mut self) {

View file

@ -211,13 +211,13 @@ impl TextRun {
font_context: &mut FontContext<FontCacheThread>,
linebreaker: &mut Option<LineBreakLeafIter>,
font_cache: &mut Vec<FontKeyAndMetrics>,
last_inline_box_ended_with_white_space: &mut bool,
last_inline_box_ended_with_collapsible_white_space: &mut bool,
on_word_boundary: &mut bool,
) {
let segment_results = self.segment_text(
font_context,
font_cache,
last_inline_box_ended_with_white_space,
last_inline_box_ended_with_collapsible_white_space,
on_word_boundary,
);
let inherited_text_style = self.parent_style.get_inherited_text().clone();
@ -282,7 +282,7 @@ impl TextRun {
&mut self,
font_context: &mut FontContext<FontCacheThread>,
font_cache: &mut Vec<FontKeyAndMetrics>,
last_inline_box_ended_with_white_space: &mut bool,
last_inline_box_ended_with_collapsible_white_space: &mut bool,
on_word_boundary: &mut bool,
) -> Vec<(TextRunSegment, FontRef)> {
let font_group = font_context.font_group(self.parent_style.clone_font());
@ -291,10 +291,11 @@ impl TextRun {
// TODO: Eventually the text should come directly from the Cow strings of the DOM nodes.
let text = std::mem::take(&mut self.text);
let white_space = self.parent_style.clone_white_space();
let collapsed = WhitespaceCollapse::new(
text.as_str().chars(),
self.parent_style.clone_white_space(),
*last_inline_box_ended_with_white_space,
white_space,
*last_inline_box_ended_with_collapsible_white_space,
);
let text_transform = self.parent_style.clone_text_transform();
@ -304,8 +305,9 @@ impl TextRun {
// `TextTransformation` doesn't support capitalization, so we must capitalize the whole
// string at once and make a copy. Here `on_word_boundary` indicates whether or not the
// inline formatting context as a whole is on a word boundary. This is different from
// `last_inline_box_ended_with_white_space` because the word boundaries are between
// atomic inlines and at the start of the IFC.
// `last_inline_box_ended_with_collapsible_white_space` because the word boundaries are
// between atomic inlines and at the start of the IFC, and because preserved spaces
// are a word boundary.
let collapsed_string: String = collapsed.collect();
collected_text = capitalize_string(&collapsed_string, *on_word_boundary);
Box::new(collected_text.chars())
@ -323,8 +325,9 @@ impl TextRun {
let current_byte_index = next_byte_index;
next_byte_index += character.len_utf8();
*last_inline_box_ended_with_white_space = character.is_whitespace();
*on_word_boundary = *last_inline_box_ended_with_white_space;
*on_word_boundary = character.is_whitespace();
*last_inline_box_ended_with_collapsible_white_space =
*on_word_boundary && !white_space.preserve_spaces();
let prevents_soft_wrap_opportunity =
char_prevents_soft_wrap_opportunity_when_before_or_after_atomic(character);

View file

@ -1,2 +0,0 @@
[white-space-mixed-002.xht]
expected: FAIL