Initially, this function was made to return CSS::Length because some of
its callers were expecting it to ignore "auto" width on input and
return it as is. Instead, let's just forbid using "auto" for input
width and always return CSSPixels.
We were incorrectly offsetting the static position of abspos children of
flex containers by the padding twice. This was a misguided attempt to
adjust to the abspos containing block being the padding box, not the
content box.
Fixes#21344.
This allows us to retain perfect precision for aspect ratios derived
from either the intrinsic sizes of replaced elements, or the
`aspect-ratio` CSS property.
This is intended to annotate conversions from unknown floating-point
values to CSSPixels, and make it more obvious the fp value will be
rounded to the nearest fixed-point value.
In general it is not safe to convert any arbitrary floating-point value
to CSSPixels. CSSPixels has a resolution of 0.015625, which for small
values (e.g. scale factors between 0 and 1), can produce bad results
if converted to CSSPixels then scaled back up. In the worst case values
can underflow to zero and produce incorrect results.
CSS-ALIGN-3 tells us that `normal` behavior inside flex containers is
simply to behave as `stretch` so this patch makes them behave the same
inside FFC.
Furthermore, we change the `align-items` initial value to `normal`,
matching other engines.
Changing `calculate_min_content_heigh()` and
`calculate_min_content_heigh()` to accept width as `CSSPixels`, instead
of `AvailableSize` that might be indefinite, makes it more explicit
that width is supposed to be known by the time height is measured.
This change has a bit of collateral damage which is rows height
calculation regression in `table/inline-table-width` that worked before
by accident.
This stuff is pretty hairy since the specifications don't give any
guidance on which widths to use when calculating the intrinsic height of
flex items in a column layout.
However, our old behavior of "treat anything indefinite as fit-content"
was definitely not good enough, so this patch improves the situation by
considering values like `min-content`, `max-content` and `fit-content`
separately from `auto`, and making the whole flex layout pipeline aware
of them (in the cross axis context).
Properties like min-width, max-width, etc, should be ignored while we're
trying to determine the intrinsic size of a flex container.
This fixes an infinite recursion when using an intrinsic size keyword as
the max-width of a flex column container.
Note that this behavior is marked as AD-HOC in code comments because
specs don't tell us how to achieve intrinsic sizing.
We can now load product pages on the Twinings site, such as
https://twinings.co.uk/products/earl-grey-100-tea-bags :^)
Auto margins used together with justify-content would previously
result in children being positioned outside their parent. This was
solved by letting auto margins take precedence when they are used,
which was already implemented to some extent before, but not
fully.
Containers with both flex reverse and justify content would
sometimes place children outside the container. This happened
because it assumed any reversed container would have items
aligned to the right, which isn't true when using eg. `flex-end`.
Both `justify-content: start` and `justify-content: end` are now
also independent of the reverseness.
After switching to fixed-point arithmetic in CSSPixels, it no longer
supports representing infinite values, which was previously the case
for remaining_free_space in FFC. Using Optional that is not empty only
when value is finite to store remaining_free_space ensures that
infinity is avoided in layout calculations.
Using fixed-point saturated arithmetics for CSSPixels allows to avoid
accumulating floating-point errors.
This implementation is not complete yet: currently saturated
arithmetics implemented only for addition. But it is enough to not
regress any of layout tests we have :)
See https://github.com/SerenityOS/serenity/issues/18566
This is the preparation to use fixed-point to represent CSSPixels.
Previously, it was acceptable to divide CSSPixels by zero, resulting
in inf, but after migrating to fixed-point stored as an integer, it
would lead to undefined behavior.
Once we've resolved the used flex item width & height, we should allow
percentage flex item sizes to resolve against them instead of forcing
flex items to always treat percentages as auto while doing intrinsic
sizing layout.
Regressed in 8dd489da61.
We do this by piggybacking on FormattingContext helpers instead of
reinventing the wheel in FlexFormattingContext.
This fixes an issue where `min-width: fit-content` (and other
layout-dependent values) were treated as 0 on flex items.
This makes the cookie banners look okay on https://microsoft.com/ :^)
Make sure the insets and margins calculated according to the spec are
not later ignored and ad-hoc recomputed in
layout_absolutely_positioned_element.
Use the static position calculation in a couple of places where the
spec (and comment) was indicating it should be used.
Fixes#19362
When sizing under a max-content constraint, we allow flex lines to have
an infinite amount of "remaining space", but we shouldn't let infinity
leak into the geometry of items. So treat it as zero in arithmetic.
This fixes an issue where inline SVGs with natural aspect ratio (from
viewBox) but no natural width or height could get an infinite size as
flex items.
Instead of a custom struct, use an AK::Variant for flex-basis.
A flex-basis is either `content` or a CSS size value, so we don't need
anything custom for that.
By using a CSS size, we also avoid having to convert in and out of size
in various places, simplifying the code.
This finally gets rid of the "Unsupported main size for flex-basis"
debug spam. :^)
Although DistinctNumeric, which is supposed to abstract the underlying
type, was used to represent CSSPixels, we have a whole bunch of places
in the layout code that assume CSSPixels::value() returns a
floating-point type. This assumption makes it difficult to replace the
underlying type in CSSPixels with a non-floating type.
To make it easier to transition CSSPixels to fixed-point math, one step
we can take is to prevent access to the underlying type using value()
and instead use explicit conversions with the to_float(), to_double(),
and to_int() methods.
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.
Having this here instead of in ReplacedBox means we can access it when
figuring out what the "preferred aspect ratio" is.
There's some inconsistency between specs about what this is called, but
they're moving towards referring to this as "natural width/height/
aspect-ratio", so let's copy that terminology.
We were incorrectly returning a "specified size suggestion" for flex
items with a definite main size where that main size was also automatic.
This led to us incorrectly choosing 0 as the automatic minimum size for
that flex item, instead of its min-content size.
If a flex item's main size is a CSS calc() value that resolves to a
length and contains a percentage, we can only resolve it when we have
the corresponding reference size for the containing block.
If the flex container is being sized under a max-content main size
constraint, there is effectively infinite space available for flex
items. Thus, flex lines should be allowed to be infinitely long.
This is a little awkward, because the spec doesn't mention specifics
about how to resolve flexible lengths during intrninsic sizing.
I've marked the spec deviations with big "AD-HOC" comments.
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.
We were not taking reverse flex directions into account when choosing
the initial offset for flex item placement if justify-content were
either space-around or space-between.
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.
1. Propagate calc() values from StyleProperties to ComputedValues.
2. Actually resolve calc() values when determining the used flex basis.
This makes the "support" section on https://shopify.com/ show up
correctly as a 2x2 grid (instead of 1x4). :^)
If there are min or max size constraints in the cross axis for a flex
item that has a desired aspect ratio, we may need to adjust the main
size *after* applying the cross size constraints.
All the steps to achieving this aren't mentioned in the spec, but it
seems that all other browsers behave this way, so we should too.
When we determine that a size is definite because it can be resolved now
without performing layout, we also need to account for the box-sizing
property.
This lets us remove a hack from flex layout where box-sizing:border-box
was manually undone at one point in the layout algorithm.
These functions no longer do anything interesting and just forward to
content_width/content_height. Let's make the callers use those directly
instead and remove this indirection layer.