Split line layout into two phases (#30089)

In the first phase, we gather LineItems and then when we have enough to
form a line we turn them into Fragments. This will make it possible to
more simply implement `vertical-align` and `text-align: justify` because
we need to measure the different aspects of the candidate line and then
produce a Fragments.

This is a general refactor of the way that inline layout works, so comes
with some progressions. In addition there are some new failures.

New failures:

Some tests are now failing because only the test or reference is getting
proper line height when it wasn't before. These should be fixed in a
followup change that properly calculate line-height in more cases:

 - /_mozilla/css/list_style_position_a.html
 - /css/CSS2/floats/float-no-content-beside-001.html
 - /css/css-content/pseudo-element-inline-box.html
 - /css/css-flexbox/flexbox_flex-none-wrappable-content.html

Some tests are now failing because floats are now placed properly, but
are no longer in their inline box stacking contexts. These will be fixed
by a followup change which properly parents them:

- /css/filter-effects/filtered-inline-applies-to-float.html.ini
- /css/css-color/inline-opacity-float-child.html.ini

One test is failing due to floating point precision errors:

- /css/CSS2/floats-clear/floats-141.xht.ini

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Mukilan Thiyagarajan <mukilan@igalia.com>
This commit is contained in:
Martin Robinson 2023-08-11 09:19:50 +02:00 committed by GitHub
parent 450f8193a5
commit 59f5414ca8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 791 additions and 659 deletions

File diff suppressed because it is too large Load diff

View file

@ -372,6 +372,7 @@ impl BlockContainer {
positioning_context, positioning_context,
containing_block, containing_block,
sequential_layout_state, sequential_layout_state,
collapsible_with_parent_start_margin,
), ),
} }
} }

View file

@ -155,6 +155,7 @@ impl BoxFragment {
\ncontent={:?}\ \ncontent={:?}\
\npadding rect={:?}\ \npadding rect={:?}\
\nborder rect={:?}\ \nborder rect={:?}\
\nmargin={:?}\
\nclearance={:?}\ \nclearance={:?}\
\nscrollable_overflow={:?}\ \nscrollable_overflow={:?}\
\noverflow={:?} / {:?}", \noverflow={:?} / {:?}",
@ -162,6 +163,7 @@ impl BoxFragment {
self.content_rect, self.content_rect,
self.padding_rect(), self.padding_rect(),
self.border_rect(), self.border_rect(),
self.margin,
self.clearance, self.clearance,
self.scrollable_overflow(&PhysicalRect::zero()), self.scrollable_overflow(&PhysicalRect::zero()),
self.style.get_box().overflow_x, self.style.get_box().overflow_x,

View file

@ -299,11 +299,12 @@ impl AnonymousFragment {
impl TextFragment { impl TextFragment {
pub fn print(&self, tree: &mut PrintTree) { pub fn print(&self, tree: &mut PrintTree) {
tree.add_item(format!( tree.add_item(format!(
"Text num_glyphs={}", "Text num_glyphs={} box={:?}",
self.glyphs self.glyphs
.iter() .iter()
.map(|glyph_store| glyph_store.len().0) .map(|glyph_store| glyph_store.len().0)
.sum::<isize>() .sum::<isize>(),
self.rect,
)); ));
} }
} }

View file

@ -32,7 +32,7 @@ pub mod flow_relative {
pub size: Vec2<T>, pub size: Vec2<T>,
} }
#[derive(Clone, Serialize)] #[derive(Clone, Debug, Serialize)]
pub struct Sides<T> { pub struct Sides<T> {
pub inline_start: T, pub inline_start: T,
pub inline_end: T, pub inline_end: T,

View file

@ -229,11 +229,8 @@ impl PositioningContext {
new_context.layout_collected_children(layout_context, &mut new_fragment); new_context.layout_collected_children(layout_context, &mut new_fragment);
// If the new context has any hoisted boxes for the nearest containing block for // If the new context has any hoisted boxes for the nearest containing block for
// all descendants than collect them and pass them up the tree. // pass them up the tree.
vec_append_owned( self.append(new_context);
&mut self.for_nearest_containing_block_for_all_descendants,
new_context.for_nearest_containing_block_for_all_descendants,
);
if style.clone_position() == Position::Relative { if style.clone_position() == Position::Relative {
new_fragment.content_rect.start_corner += new_fragment.content_rect.start_corner +=
@ -305,16 +302,38 @@ impl PositioningContext {
.push(box_) .push(box_)
} }
fn is_empty(&self) -> bool {
self.for_nearest_containing_block_for_all_descendants
.is_empty() &&
self.for_nearest_positioned_ancestor
.as_ref()
.map_or(true, |vector| vector.is_empty())
}
pub(crate) fn append(&mut self, other: Self) { pub(crate) fn append(&mut self, other: Self) {
if other.is_empty() {
return;
}
vec_append_owned( vec_append_owned(
&mut self.for_nearest_containing_block_for_all_descendants, &mut self.for_nearest_containing_block_for_all_descendants,
other.for_nearest_containing_block_for_all_descendants, other.for_nearest_containing_block_for_all_descendants,
); );
match ( match (
self.for_nearest_positioned_ancestor.as_mut(), self.for_nearest_positioned_ancestor.as_mut(),
other.for_nearest_positioned_ancestor, other.for_nearest_positioned_ancestor,
) { ) {
(Some(a), Some(b)) => vec_append_owned(a, b), (Some(us), Some(them)) => vec_append_owned(us, them),
(None, Some(them)) => {
// This is the case where we have laid out the absolute children in a containing
// block for absolutes and we then are passing up the fixed-position descendants
// to the containing block for all descendants.
vec_append_owned(
&mut self.for_nearest_containing_block_for_all_descendants,
them,
);
},
(None, None) => {}, (None, None) => {},
_ => unreachable!(), _ => unreachable!(),
} }
@ -378,6 +397,7 @@ impl PositioningContext {
} }
/// A data structure which stores the size of a positioning context. /// A data structure which stores the size of a positioning context.
#[derive(PartialEq)]
pub(crate) struct PositioningContextLength { pub(crate) struct PositioningContextLength {
/// The number of boxes that will be hoisted the the nearest positioned ancestor for /// The number of boxes that will be hoisted the the nearest positioned ancestor for
/// layout. /// layout.

View file

@ -55,6 +55,7 @@ pub(crate) enum DisplayInside {
} }
/// Percentages resolved but not `auto` margins /// Percentages resolved but not `auto` margins
#[derive(Clone)]
pub(crate) struct PaddingBorderMargin { pub(crate) struct PaddingBorderMargin {
pub padding: flow_relative::Sides<Length>, pub padding: flow_relative::Sides<Length>,
pub border: flow_relative::Sides<Length>, pub border: flow_relative::Sides<Length>,

View file

@ -1,2 +0,0 @@
[remove-block-between-inline-and-abspos.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[block-in-inline-007.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[floats-141.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[float-no-content-beside-001.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[float-nowrap-4.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[floats-placement-vertical-001b.xht]
expected: FAIL

View file

@ -1,2 +0,0 @@
[floats-placement-vertical-001c.xht]
expected: FAIL

View file

@ -1,2 +0,0 @@
[block-non-replaced-width-007.xht]
expected: FAIL

View file

@ -1,2 +0,0 @@
[text-indent-on-blank-line-rtl-left-align.html]
expected: FAIL

View file

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

View file

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

View file

@ -1,2 +0,0 @@
[stack-floats-003.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[inline-opacity-float-child.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[pseudo-element-inline-box.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[flexbox_flex-none-wrappable-content.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[position-relative-003.html]
expected: TIMEOUT

View file

@ -1,2 +0,0 @@
[position-relative-004.html]
expected: TIMEOUT

View file

@ -0,0 +1,2 @@
[filtered-inline-applies-to-float.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[input_whitespace.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[list_style_position_a.html]
expected: FAIL