Calculate a "preferred aspect ratio" based on the value of
`aspect-ratio` and the presence of a natural aspect ratio, and use that
in layout.
This is by no means complete or perfect, but we do now apply the given
aspect-ratio to things.
The spec is a bit vague, just saying to calculate sizes for
aspect-ratio'ed boxes the same as you would for replaced elements. My
naive solution here is to find everywhere we were checking for a
ReplacedBox, and then also accept a regular Box with a preferred aspect
ratio. This gets us pretty far. :^)
https://www.w3.org/TR/css-sizing-4/#aspect-ratio-minimum is not at all
implemented.
If a box has a negative margin-left, it may have a negative effective
offset within its parent BFC root coordinate system.
We can account for this when calculating the amount of left-side float
intrusion by flooring the X offset at 0.
Instead of just measuring the layout viewport, we now measure overflow
in every box that is a scroll container.
This has the side effect of no longer creating paintables for layout
boxes that didn't participate in layout. (For example, empty/anonymous
boxes that were ignored by flex itemization.)
Such boxes are now marked as "(not painted)" in the layout tree dumps,
as they have no paintable to dump geometry from.
These are only used during layout, and always within formatting context
code, so we might as well put them in FormattingContext and avoid having
to pass the LayoutState around all the time.
At one point in the past, we had some functions that were called across
different formatting context types, which necessitated making them
static and taking the LayoutState as a parameter.
In all cases, those functions were used to do incorrect hacks, all of
which we've replaced with more correct solutions. :^)
Separating the paths for replaced and non-replaced floating boxes lost
the logic for margin, padding and border which was done by
compute_width_for_floating_box. Set them the same way as we do for
block-level replaced elements, per the specification.
Solves conflict in layout tree "type system" when elements <label> (or
<button>) can't have `display: table` because Box can't be
Layout::Label (or Layout::ButtonBox) and Layout::TableBox at the same
time.
The path for floating, replaced elements must not fall through to the
path taken for floating, non-replaced elements. The former works like
inline replaced elements, while the latter uses a completely different
algorithm which doesn't account for intrinsic ratio. Falling through
overrides the correct value computed by the former.
Fixes#19061.
This fixes the issue when margin collapsing state was always reset if
a box has clear property not equal to none even if it does not actually
introduce clearance.
This fixes the issue where max margin is used to find offset of
floating box although horizonal margins do not collapse so they need
to be summed instead.
This fixes a plethora of rounding problems on many websites.
In the future, we may want to replace this with fixed-point arithmetic
(bug #18566) for performance (and consistency with other engines),
but in the meantime this makes the web look a bit better. :^)
There's a lot more things that could be converted to doubles, which
would reduce the amount of casting necessary in this patch.
We can do that incrementally, however.
Previously, calling `.right()` on a `Gfx::Rect` would return the last
column's coordinate still inside the rectangle, or `left + width - 1`.
This is called 'endpoint inclusive' and does not make a lot of sense for
`Gfx::Rect<float>` where a rectangle of width 5 at position (0, 0) would
return 4 as its right side. This same problem exists for `.bottom()`.
This changes `Gfx::Rect` to be endpoint exclusive, which gives us the
nice property that `width = right - left` and `height = bottom - top`.
It enables us to treat `Gfx::Rect<int>` and `Gfx::Rect<float>` exactly
the same.
All users of `Gfx::Rect` have been updated accordingly.
We have to special-case these, otherwise our normal CSS layout algorithm
will see that some SVG roots have width/height assigned, and make those
the used width/height.
When used in an SVG-as-image context, the outermost viewport must be the
authoritative root size.
There are a couple of things that went into this:
- We now calculate the intrinsic width/height and aspect ratio of <svg>
elements based on the spec algorithm instead of our previous ad-hoc
guesswork solution.
- Replaced elements with automatic size and intrinsic aspect ratio but
no intrinsic dimensions are now sized with the stretch-fit width
formula.
- We take care to assign both used width and used height to <svg>
elements before running their SVG formatting contexts. This ensures
that the inside SVG content is laid out with knowledge of its
viewport geometry.
- We avoid infinite recursion in tentative_height_for_replaced_element()
by using the already-calculated used width instead of calling the
function that calculates the used width (since that may call us right
back again).
In order to fix this, I also had to reorganize the code so that we
create an independent formatting context even for block-level boxes
that don't have any children. This accidentally improves a table
layout test as well (for empty tables).
This code now works in terms of *intrusion* by left and right side
floats into a given box whose insides we're trying to layout.
Previously, it worked in terms of space occupied by floats in the root
box of the BFC they participated in. That created a bunch of edge cases
since the code asking about the information wasn't operating in root
coordinate space, but in the coordinate space of some arbitrarily nested
block descendant of the root.
This finally allows horizontal margins in the containing block chain to
affect floats and nested content correctly, and it also allows us to
remove a bogus workaround in InlineFormattingContext.
If the parent BFC can come up with a nice stretch-fit width for the flex
container, it will have already done so *before* even entering flex
layout. There's no need to do it again, midway through the flex layout
algorithm.
This wasn't just unnecessary, but we were also doing it incorrectly and
not taking margins into account when calculating the amount of available
space for stretch-fit. This led to oversized flex containers in the
presence of negative margins.
Fixes#18614
`calculate_max_content_height` expects the available width as the
second argument. However, the available height was mistakenly passed
before. This did not seem to cause any problems because TFC currently
does not respect height sizing constraints but still needs to be fixed.
Width of table wrapper need to be set to to calculate width of table
box inside. Otherwise TFC will set wrong width assuming width of
containing block is 0.
https://www.w3.org/TR/CSS22/visuren.html#floats says that when a box
establishes BFC it should not overlap with floats. The way to avoid
overlaps is up to implementor. This change implements avoiding overlap
by narrowing width of a box because it seems like what other engines
do (in the scenarios I tested).
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)