Skip to content

Commit

Permalink
Allow pre-wrap whitespace to hang at the end of the line (#31681)
Browse files Browse the repository at this point in the history
* Allow pre-wrap whitespace to hang at the end of the line

* Use bitflags
  • Loading branch information
Loirooriol committed Mar 15, 2024
1 parent ac24cd6 commit 39f660f
Show file tree
Hide file tree
Showing 24 changed files with 54 additions and 64 deletions.
72 changes: 54 additions & 18 deletions components/layout_2020/flow/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ use std::cell::OnceCell;
use std::mem;

use app_units::Au;
use bitflags::bitflags;
use gfx::font::FontMetrics;
use gfx::text::glyph::GlyphStore;
use serde::Serialize;
Expand Down Expand Up @@ -1215,7 +1216,11 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
.current_inline_container_state()
.strut_block_sizes
.clone();
self.update_unbreakable_segment_for_new_content(&strut_size, Length::zero(), false);
self.update_unbreakable_segment_for_new_content(
&strut_size,
Length::zero(),
SegmentContentFlags::empty(),
);
}

self.had_inflow_content = true;
Expand Down Expand Up @@ -1243,12 +1248,11 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
font_index: usize,
) {
let inline_advance = Length::from(glyph_store.total_advance());
let preserve_spaces = text_run
.parent_style
.get_inherited_text()
.white_space
.preserve_spaces();
let is_collapsible_whitespace = glyph_store.is_whitespace() && !preserve_spaces;
let flags = if glyph_store.is_whitespace() {
SegmentContentFlags::from(text_run.parent_style.get_inherited_text().white_space)
} else {
SegmentContentFlags::empty()
};

// If the metrics of this font don't match the default font, we are likely using a fallback
// font and need to adjust the line size to account for a potentially different font.
Expand All @@ -1270,7 +1274,7 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
container_state.get_block_size_contribution(vertical_align, &font_metrics);
block_size.adjust_for_baseline_offset(container_state.baseline_offset);
block_size
} else if quirks_mode && !is_collapsible_whitespace {
} else if quirks_mode && !flags.is_collapsible_whitespace() {
// Normally, the strut is incorporated into the nested block size. In quirks mode though
// if we find any text that isn't collapsed whitespace, we need to incorporate the strut.
// TODO(mrobinson): This isn't quite right for situations where collapsible white space
Expand All @@ -1281,11 +1285,7 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
} else {
LineBlockSizes::zero()
};
self.update_unbreakable_segment_for_new_content(
&strut_size,
inline_advance,
is_collapsible_whitespace,
);
self.update_unbreakable_segment_for_new_content(&strut_size, inline_advance, flags);

match self.current_line_segment.line_items.last_mut() {
Some(LineItem::TextRun(line_item)) if ifc_font_info.key == line_item.font_key => {
Expand All @@ -1309,14 +1309,16 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
&mut self,
block_sizes_of_content: &LineBlockSizes,
inline_size: Length,
is_collapsible_whitespace: bool,
flags: SegmentContentFlags,
) {
if !is_collapsible_whitespace {
if flags.is_collapsible_whitespace() || flags.is_wrappable_whitespace() {
self.current_line_segment.trailing_whitespace_size = inline_size;
} else {
self.current_line_segment.trailing_whitespace_size = Length::zero();
}
if !flags.is_collapsible_whitespace() {
self.current_line_segment.has_content = true;
self.had_inflow_content = true;
} else {
self.current_line_segment.trailing_whitespace_size = inline_size;
}

// This may or may not include the size of the strut depending on the quirks mode setting.
Expand Down Expand Up @@ -1442,6 +1444,36 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> {
}
}

bitflags! {
pub struct SegmentContentFlags: u8 {
const COLLAPSIBLE_WHITESPACE = 0b00000001;
const WRAPPABLE_WHITESPACE = 0b00000010;
}
}

impl SegmentContentFlags {
fn is_collapsible_whitespace(&self) -> bool {
self.contains(Self::COLLAPSIBLE_WHITESPACE)
}

fn is_wrappable_whitespace(&self) -> bool {
self.contains(Self::WRAPPABLE_WHITESPACE)
}
}

impl From<WhiteSpace> for SegmentContentFlags {
fn from(white_space: WhiteSpace) -> Self {
let mut flags = Self::empty();
if !white_space.preserve_spaces() {
flags.insert(Self::COLLAPSIBLE_WHITESPACE);
}
if white_space.allow_wrap() {
flags.insert(Self::WRAPPABLE_WHITESPACE);
}
flags
}
}

enum InlineFormattingContextIterItem<'a> {
Item(&'a mut InlineLevelBox),
EndInlineBox,
Expand Down Expand Up @@ -2088,7 +2120,11 @@ impl IndependentFormattingContext {

let (block_sizes, baseline_offset_in_parent) =
self.get_block_sizes_and_baseline_offset(ifc, size.block, baseline_offset);
ifc.update_unbreakable_segment_for_new_content(&block_sizes, size.inline, false);
ifc.update_unbreakable_segment_for_new_content(
&block_sizes,
size.inline,
SegmentContentFlags::empty(),
);
ifc.push_line_item_to_unbreakable_segment(LineItem::Atomic(AtomicLineItem {
fragment,
size,
Expand Down
2 changes: 0 additions & 2 deletions tests/wpt/meta/css/css-text/hyphens/hyphens-auto-002.html.ini

This file was deleted.

This file was deleted.

This file was deleted.

2 changes: 0 additions & 2 deletions tests/wpt/meta/css/css-text/white-space/pre-wrap-001.html.ini

This file was deleted.

2 changes: 0 additions & 2 deletions tests/wpt/meta/css/css-text/white-space/pre-wrap-002.html.ini

This file was deleted.

2 changes: 0 additions & 2 deletions tests/wpt/meta/css/css-text/white-space/pre-wrap-003.html.ini

This file was deleted.

2 changes: 0 additions & 2 deletions tests/wpt/meta/css/css-text/white-space/pre-wrap-004.html.ini

This file was deleted.

2 changes: 0 additions & 2 deletions tests/wpt/meta/css/css-text/white-space/pre-wrap-005.html.ini

This file was deleted.

2 changes: 0 additions & 2 deletions tests/wpt/meta/css/css-text/white-space/pre-wrap-006.html.ini

This file was deleted.

2 changes: 0 additions & 2 deletions tests/wpt/meta/css/css-text/white-space/pre-wrap-007.html.ini

This file was deleted.

2 changes: 0 additions & 2 deletions tests/wpt/meta/css/css-text/white-space/pre-wrap-015.html.ini

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

2 changes: 0 additions & 2 deletions tests/wpt/mozilla/meta/css/white-space-pre-wrap.htm.ini

This file was deleted.

0 comments on commit 39f660f

Please sign in to comment.