Allow pre-wrap whitespace to hang at the end of the line (#31681)

* Allow pre-wrap whitespace to hang at the end of the line

* Use bitflags
This commit is contained in:
Oriol Brufau 2024-03-15 17:12:41 +01:00 committed by GitHub
parent ac24cd6139
commit 39f660f520
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 54 additions and 64 deletions

View file

@ -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;
@ -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;
@ -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.
@ -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
@ -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 => {
@ -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.
@ -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,
@ -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,