Sometimes column Flexbox needs to do an early layout pass to determine
the preferred block content size of flex items. Previously the
absolutely positioned children created during this pass were discarded,
but now they are cached to be possibly used during the final layout
phase of the flex item. Since they are not thrown away, it is necessary
that the `PositioningContext` used to collect them is compatible with
their final `PositioningContext`.
Fixes#36121.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This replaces `IndependentLayout` with `CacheableLayoutResult` and
stores it in `LayoutBoxBase` so it can be reused when we need to lay out
a box multiple times.
This is a generalization of the caching that we had for flexbox, which
is now removed in favor of the new one.
With this, the number of runs per second in the Chromium perf test
`flexbox-deeply-nested-column-flow.html` are multiplied by 3.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
Spec: https://drafts.csswg.org/css-sizing-3/#funcdef-width-fit-content
It's similar to the `fit-content` keyword but, instead of clamping the
stretch size between `min-content` and `max-content`, it clamps the
provided argument.
So now that we support `fit-content`, it's quite straightforward to add.
It's just not completely clear what should happen when the argument has
a cyclic percentage, so this may need some further adjustments depending
on the outcome of https://github.com/w3c/csswg-drafts/issues/11805
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
We were ignoring sizing keywords on the min and max sizing properties.
With this, flexbox layout has full support for sizing keywords.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Adds support for min-content, max-content, fit-content and stretch on
the min and max main size properties of a flex item.
I'm removing `automatic_min_size()` and `flex_base_size()` because they
would need to share so much code among themselves and their one caller
that it's simpler to just inline the code.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
These methods were doing virtually the same thing. So this patch moves
the common logic into a new `FlexItemBox::to_flex_item()`, which is then
called by `FlexItem::new()` and `FlexItemBox::main_content_size_info()`.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
`Size::resolve_for_min()` had an `Au` parameter, representing the value
to be used for an automatic minimum size. However, this amount isn't
trivial to compute in flexbox, so this patch changes the parameter to a
function that can be called lazily.
Note flexbox isn't currently using `Size::resolve_for_min()`, but it
will in #35961.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
In particular:
- `z-index` will now work on unpositioned grid items.
- `will-change: z-index` will only establish a stacking context if
`z-index` applies, i.e. if the box is positioned or a flex/grid item.
- The conditions in `establishes_stacking_context()` are reordered,
so that the most likely ones are checked first.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
One of the callers was only used for an assert, and it was passing an
inline size argument to a parameter expecting a block size, so it wasn't
making much sense anyways.
Just inline the code into the other caller, and for consistency remove
the assert for replaced elements too.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Adds support for min-content, max-content, fit-content and stretch on
the min and max cross size properties of a flex item.
With one exception: when resolving the main sizes, transferred cross
minimums and maximums will still ignore keywords.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This changes `FlexItem::content_cross_size` into `Size<Au>` to preserve
keyword sizes. The calculation of the hypothetical cross size still
ignores them though, that will be addressed in a follow-up.
Also, browsers don't follow the spec and treat a stretch size different
than a stretch alignment: the former stretches to the containing block,
while the latter stretches to the line. This aligns Servo with that
behavior (following the spec would require bigger refactorings), so
`stretches()` is renamed to `stretches_to_line()` for clarity.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
* Use 2024 style edition
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Reformat all code
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
An intrinsic flex base size depends on the contents, which may depend on
the cross size through an aspect ratio. We were only taking this into
account if the preferred cross size was numeric, but `auto` or `stretch`
can also be definite.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
The computation of the flex base size may involve transferring a
definite cross size into the main axis through the aspect ratio.
We were only considering numeric sizes as definite, but `stretch` can
also be definite.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
The computation of the automatic minimum size may involve transferring
a definite cross size into the main axis through the aspect ratio.
We were only considering numeric sizes as definite, but `stretch` can
also be definite.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This method was taking an `IndefiniteContainingBlock` parameter, and
then it would first take the size corresponding to the main axis, and
then the one for the cross axis.
But it's simpler to just let it take a `FlexRelativeVec2<AuOrAuto>`
parameter.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
* Update to rust 1.85
This is needed for cargo-deny
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Upgrade crown
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Clippy fixes
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Re-upgrade cargo-deny to 0.18
Keeping it locked to 0.18 just in case they
update their required rustc version again
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
We were always treating an indefinite `stretch` as the automatic size.
This instead treats it as `0px` on min sizing properties, and as `none`
on max sizing properties, aligning with Blink and this recent CSSWG
resolution: https://github.com/w3c/csswg-drafts/issues/11006
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
* Add tests for sizing keywords on flex items
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
* layout: Partial support for sizing keywords on flex items
When a flex item has `flex-basis: auto`, the used `flex-basis` is the
value of the main size property. In that case, if the main size property
was set to keyword, we were always assuming it was `auto`. Now we handle
non-`auto` keywords correctly.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
---------
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
layout: Basic implementation of size keywords on `flex-basis`
This splits the logic to resolve the used value of `flex-basis` into its
own method, which preserves size keywords.
And then it changes `flex_base_size()` to resolve the provided keywords
properly. However, it doesn't handle size keywords in the cross axis.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Thanks to #34946 we don't have to recompute the min and max sizes, we
can get them from the `ContainingBlock`.
And then in `FlexContext` there is no need to store both the definite
and the min & max sizes of the container`, we can instead make do with
a single `FlexRelativeVec2<SizeConstraint>`.
This removes 1 of the 3 usages of `ContentBoxSizesAndPBMDeprecated`,
which is also good.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
If an absolutely position element which is replaced has `justify-self`
or `align-self` set to `stretch`, and no inset is `auto` on that axis,
then an automatic size should behave as `stretch`, not as `fit-content`.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Some layouts like table need some style overrides. We were handling this
in `ComputedValuesExt`, but it was messy, unreliable and too limited.
For example, we were assuming that a style with `display: table` would
belong to a table wrapper box or table grid box. However, certain HTML
elements can ignore their `display` value and generate a different kind
of box. I think we aren't doing that yet, but we will need this.
Also, resolving the used border of a table needs layout information,
which we don't have in `ComputedValuesExt`. This patch will allow to
improve border collapsing in a follow-up.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
It used to be an `AuOrAuto`, turning it into a `SizeConstraint` allows
passing the information about the min and max constraints when the
containing block doesn't have a definite block size.
This will be useful for table layout.
Note that in most cases we were already constructing the containing
block from a `SizeConstraint`, but we were calling `to_auto_or()` to
turn it into an `AuOrAuto`.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Push the interior mutability into enum variants of `Fragment`, so that
they can be cloned. This saves memory in the `Fragment` tree as the
`Fragment` enum is now a relatively wee 16 bytes and the interior parts
can be a variety of sizes. Before, every `Fragment` was the size of the
biggest kind (`BoxFragment` - 248 bytes).
This a step on the way toward incremental layout.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
The new version of rust allows us to elide some lifetimes and clippy is
now complaining about this. This change elides them where possible and
removes the clippy exceptions.
Fixes#34804.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
in each layout logic, in order to correctly resolve sizing keywords.
This patch adds a new `Sizes` struct which holds the preferred, min and
max sizing values for one axis, and unifies the logic to resolve the
final size into there.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Manage `<iframe>` size updates in `Window`. In addition to removing
duplicated code, this will allow setting `<iframe>` sizes synchronously
on child `Pipeline`s of the same origin in the script process in a
followup change. The goal is remove flakiness from `<iframe>` sizing.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Several structs and enums had a `inline_content_sizes()` method, but it
wasn't clear which ones would try to cache the result, and which ones
would always compute it.
Therefore, this performs some clarifying renaming:
- Cached ones stay as `inline_content_sizes()`
- Uncached ones become `compute_inline_content_sizes()`
Also, to simplify calls to `LayoutBoxBase::inline_content_sizes()`,
`compute_inline_content_sizes()` is moved into a new trait.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
The refactoring in 264c0f972f stopped
caching the `inline_content_sizes()` calls from:
- `FlexItemBox::layout_for_block_content_size()`
- `IndependentFormattingContext::layout_float_or_atomic_inline()`
- `TaffyContainerContext::compute_child_layout()`
Also, the call from `OutsideMarker::layout()` was never cached.
This patch caches all of them.
It's not clear at all which `inline_content_sizes()` are cached and
which aren't, so I plan to improve the situation in a follow-up.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This might make caching these values a bit easier in the future.
Correcting the visibility of `ContainingBlock` also exposed some new
rustc and clippy warnings that are fixed here.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
Add a new struct `LayoutBoxBase`, that will be used throughout the box
tree. The idea of this struct is that we have a place to consistently
store common layout information (style and node information) and also to
cache layout results such as content sizes (inline and maybe later box
sizes) and eventually layout results.
In addition to the addition of this struct,
`IndependentFormattingContext` is flattened slightly so that it directly
holds the contents of both replaced and non-replaced elements.
This is only added to independent formatting contexts, but will later be
added to all block containers as well.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
* Obey min and max properties when computing main size of column flex
When laying out a column flex container with an auto preferred main size,
we were resolving the used main size to the intrinsic max-content size.
However, we weren't clamping this amount between the min and max sizes.
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
* Improve performance of flex column layouts by caching
We were already using a cache for layout_for_block_content_size(), but
we were only storing the intrinsic block size. Thus when laying out the
flex items for real, we would perform new layouts, triggering an
exponential complexity in case of nested flexboxes.
Now we cache the entire layout result so that we can avoid doing the
work again.
This improves the results of flexbox-deeply-nested-column-flow.html
(a Blink perf test) from ~40 runs/second to ~500 runs/second on my PC.
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
---------
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
When laying out a column flex container with an auto preferred main size,
we were resolving the used main size to the intrinsic max-content size.
However, we weren't clamping this amount between the min and max sizes.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
* Refactor computation of preferred aspect ratios
Computing min/max-content sizes required a ContainingBlock in order to
resolve the padding and border when determining the preferred aspect
ratio. However, all callers already knew the padding and border, so they
can compute the ratio themselves, and pass it directly instead of
the ContainingBlock.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
* Put preferred aspect ratio into ConstraintSpace
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
---------
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
We were using the preferred aspect ratio provided by the `aspect-ratio`
property instead of the natural aspect ratio. However, the preferred
aspect ratio should only be used to size the replaced element. To paint
the replaced contents into that element we need the natural ratio.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
- Clamp the stretch size to not be negative when the sum of padding,
borders and margins exceed the available space. This avoids a 2nd
layout.
- Avoid computing the inline content sizes if the result isn't needed.
- Instead of clamping both the min-content and max-content sizes to be
between the min and max constraints, just compute the fit-content size
first, and then clamp. Then `ContentSizes::map()` can be removed.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
If a flex item in a single-line column flex container stretches, then
we can know its final size. So instead of first laying it out using its
intrinsic inline size, and then stretching it later, we can use the
correct size from the very beginning.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
* Clean up tracing instrumentation
Signed-off-by: Delan Azabani <dazabani@igalia.com>
* Set all tracing spans to trace level for now
Signed-off-by: Delan Azabani <dazabani@igalia.com>
---------
Signed-off-by: Delan Azabani <dazabani@igalia.com>
In order to support size keywords in block layout, we may need to call
`inline_content_sizes()` in order to compute the min/max-content sizes.
But this required a mutable reference in order the update the cache,
and in various places we already had mutable references.
So this switches the cache into a RwLock to avoid needing mutable refs.
Note OnceCell wouldn't work because it's not thread-safe.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
To compute the min-content and max-content inline sizes of a replaced
element, we were only using the aspect ratio to transfer definite block
sizes resulting from clamping the preferred block size between the min
and max block sizes.
However, if the preferred block size is indefinite, then we weren't
transfering the min and max through the aspect ratio.
This patch adds a `SizeConstraint` enum that can represent these cases,
and a `ConstraintSpace` struct analogous to `IndefiniteContainingBlock`
but with no inline size, and a `SizeConstraint` block size.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>