Calculating width of a box in BFC requires having resolved y to be able
to check if a box overlaps with any floating boxes.
This change makes compute_width() to be called after finding y
position. That also required to move resolving of vertical metrics
in the beginning of a box layout process to have vertical margins
resolved before finding y position.
When there are floats present inside an IFC, we must coordinate with
the parent BFC to calculate the automatic width of the IFC's block box.
This is because the IFC is not directly aware of floats. Only the BFC
knows enough about them to account for them in automatic sizing.
Fixes the problem that width is incorrectly computed in intrinsic
sizing mode when there are blocks that have min-width or max-width
specified.
Actually that is just the fix of a symptom of the larger problem that
Length::to_px() returns 0 when value is auto regardless of available
size.
This fix resolves issue where calculating the min size of a block could
result in incorrect value if width of the block's children was
compensated by margins to fit into container width (which is equal to 0
during min size calculation).
If there is a remaining margin-bottom in margin collapsing state
tracker after laying out all boxes in the current BFC, it must be
assigned to the last in-flow child since margin collapsing cannot
occur across a formatting context boundary.
The current issue where margin-bottom may be counted twice due to
"collapse through" margins in the last in-flow child box is addressed
with this fix by excluding such boxes during the search for a box to
assign the remaining margin.
Test case coming with this fix has a layout bug with incorrectly
computed line height.
When calculating the intrinsic width of a block-level box, we now ignore
the preferred width entirely, and not just when the preferred width
should be treated as auto.
The condition for this was both confused and wrong, as it looked at the
available width around the box, but didn't check for a width constraint
on the box itself.
Just because the available width has an intrinsic sizing constraint
doesn't mean that the box is undergoing intrinsic sizing. It could also
be the box's containing block!
Instead of special-casing FlexFormattingContext in the intrinsic sizing
layout helpers, add FormattingContext::automatic_content_width() and let
each context subclass decide what that means.
No behavior change here, just moving this responsibility.
If normal flow layout has caused us to progress past the current
innermost float in the block axis, we still need to consider the floats
stacked outside of it.
Fix this by always walking the currently stacked floats from innermost
to outermost when placing new floats.
The name "initial containing block" was wrong for this, as it doesn't
correspond to the HTML element, and that's specifically what it's
supposed to do! :^)
If a box has clearance and margin bottom of preceding box is greater
than static y of the box then it should also affect y offset in current
block container so subsequent boxes will get correct y position too.
Though table wrappers are anonymous block containers (because
TableWrapper is inherited from BlockContainer) with no lines they
should not be skipped in block auto height calculation.
Previously block auto height calculation was changed to skip boxes with
collapsed margins and then condition to skip anonymous boxes with no
lines was also removed in 6c5ba10bb0 to
avoid skipping anonymous wrappers of tables.
Skipping boxes with collapsed margins (currently it's check that
height is 0) is wrong because it makes empty boxes with clearance to
be skipped which is not correct while anonymous boxes with no lines
should be skipped and it's no longer causes problems with tables
(fixed in 87f0e835eb)
Commit 7dc0edcb86 was supposed to prevent
floats from being placed higher than preceding boxes but the change
turned out to be completely wrong and caused regressions because:
1. Call to `clear()` in `layout_block_level_children` would reset
floating boxes only after layout of box with _not_ inline children
although the same should happen after layout of IFC.
2. `clear()` causes offset y of floats to be reset but it also clears
all currently enocuntered floating boxes which means the next box
that has actual clearance will get wrong y position.
There is a difference in y offset position calculation for floats when
LineBuilder provides final y position while for blocks it needs to be
adjusted by `y_offset`. This difference already accounted in floating
box position calculation and this patch also makes it accounted in check
whether a floating boxes on the same line intersect between each other.
Change `compute_auto_height_for_block_level_element` to use max height
(`m_automatic_content_height` produced from TFC) for tables with auto
height which is more correct behaviour than treating them like block
containers.
CSS 2.2 section 9.5.1:
The outer top of a floating box may not be higher than the
outer top of any _block_ or floated box generated by an
element earlier in the source document.
Where block is `BlockContainer` in LibWeb type system.
Which means `current_boxes` need to be cleared before
leaving block container.
```html
<style>
.wrapper {
width: 100px;
height: 300px;
background-color: lightgray;
}
.box {
margin: 10px;
width: 50px;
height: 50px;
float: left;
}
.a { background-color: salmon; }
.b { background-color: slateblue; }
.c { background-color: green; }
</style>
<div class="wrapper">
<div class="box a"></div>
<div class="box b"></div>
</div>
<div class="box c">
</div>
```
Introduce `TableWrapper` type so table wrappers could be
distinguished from block containers and override width
calculation for table wrappers (CSS 2.2 spec, section 17.5.2)
inside BFCs in the way that their width should be equal to
width of table box they wrap.
This change fixes problem that y position of blocks with
clearance might not include border_top and padding_top
by changing `place_block_level_element_in_normal_flow_vertically`
to accept y position without `border_box_top` and adding it
on the last step when clearance is already taken in account.
Bug reproducer:
```html
<style>
.a {
border: 10px salmon solid;
width: 50px;
height: 50px;
float: left;
}
.b {
clear: both;
border: 20px slateblue solid;
width: 50px;
height: 50px;
}
</style>
<div class="a"></div><div class="b"></div><div class="c"></div>
```
It is incorrect to skip anonymous block containers without
line boxes during block auto height calculation because there
might be table roots wrapped in anonymous table boxes after fixup
and their height should be taken in account so leaving just
condition to skip child boxes which margins are "collapsed
through" (`border_box_height() == 0`) sufficient to skip
anonymous blocks without lines but still consider table wrappers.
Implement collapsing of a box margin-top and first in-flow
child margin-top by saving function that updates y position
of containing block inside BlockMarginState and then for
every child until "non-collapsed through" child is reached
y position of containing block is updated by calling
update_box_waiting_fox_final_y_position_callback.
Previously y position of boxes in block formatting context
was calculated by looking at y position of previous in-flow
sibling and adding collapsed margin of "collapse through"
boxes lying between box currently being laid out and it's
previous in-flow sibling.
Here introduced BlockMarginState structure that maintains
array of currently collapsible margins hence we no longer
need to look at previous sibling to calculate y position
of a box.
Bug was introduced in 210bf8adf0c431be05659140fd6de3a2cc5b7d99
It makes new variable for independent_formatting_context instead
of using earlier declared one which means that
parent_context_did_dimension_child_root_box will never be called.
This fixes a few sizing issues too. The page size is now correct in most
cases! \o/
We get to remove some of the `to_type<>()` shenanigans, though it
reappears in some other places.
Even if block has all children inline there need to be a check
if it creates BFC because otherwise IFC will be looking in
wrong parent BFC to calculate space used by floats.
We were neglecting to resolve the used horizontal padding and border
properties on block-level boxes when treating their width as `auto`
during intrinsic sizing.
This led to padding and border not contributing to the intrinsic width
of their containing block
Calling parent_context_did_dimension_child_root_box immediately after
laying out the inside of the floating box is not correct, as we haven't
worked out the dimensions of the floating box yet.
In particular, this caused the icons in the top bar of Cookie Clicker
to not hug the top of the viewport. This is because the icons are
absolutely positioned elements inside a floating element which has
padding applied to it. Since we laid out the abspos element before
the floating element, it got padding values of 0 from the parent, the
default value, meaning it didn't take away the padding of it's floating
parent.
This follows how abspos boxes layout their inside boxes as well.
We were incorrectly resolving them against the available width, which
may or may not be the same as the containing block width.
The specification for these properties says that percentages resolve
against the containing block width, so that's what we should do.