Commit graph

104 commits

Author SHA1 Message Date
Andreas Kling
85f2f8ab3f LibWeb: Make sure we layout absolutely positioned children of FFC 2022-06-21 20:17:28 +02:00
Andreas Kling
57feb0f3ec LibWeb: Add missing null check of independent formatting context in FFC
When calling layout_inside() on a flex item that can't have children of
its own, layout_inside() will not return an independent formatting
context, so we need to handle that case here.
2022-04-11 01:20:24 +02:00
Andreas Kling
cc77c82383 LibWeb: Follow relaxed CSS clamping rules in flexbox layout
AFAICT, css-values-4 tells us that clamping numbers to a range where
min>max is okay. That means we can't use AK::clamp() since it will
VERIFY that max>=min.

This patch adds a css_clamp() helper (locally in FFC for now).

This fixes an issue where a bunch of sites were crashing due to the
VERIFY in AK::clamp().
2022-04-09 14:50:05 +02:00
Andreas Kling
922509c1a5 LibWeb: Remove incorrect comment from FFC flex item cross sizing 2022-04-06 14:43:00 +02:00
Andreas Kling
c8240e31a1 LibWeb: Implement basic intrinsic sizing algorithms for flex containers
This patch adds support for MinContent and MaxContent layout to FFC.
This means that an FFC can now calculate intrinsic sizes for the flex
container, to be used by the parent formatting context.

There are some FIXME's as usual, but this already works on basic things.
2022-04-06 11:31:08 +02:00
Enver Balalic
747f347b75 LibWeb: Implement flex reverse layouts
This builds on the work done by implementing the flex order CSS
property and implements flex reverse layouts by just reversing
the order and the items within each order bucket.
2022-04-02 19:01:14 +02:00
Enver Balalic
58398b1e12 LibWeb: Implement the flex order CSS property
Adds support for the flex order property and a test page for it
on the browser welcome page.
2022-04-02 18:40:32 +02:00
Enver Balalic
7be57c322e LibWeb: Flex fix minimum main size in min/max violations calculation
While calculating the minimum size for main min/max size violations
we were flooring the min size to 0 if the item doesn't have a min
main size. Instead of that determine the intrinsic min main size
of that element.

This fixes the flex: 80% 0 4/1/0 test case in the flex.html
test page.

This case was missed in a previous commit that added the
determine_min_main_size_of_child function
2022-03-31 21:09:41 +02:00
Enver Balalic
8b4d09932a LibWeb: Fix sizing of flex child that has flex-basis 0
Before if an element didn't have a main min size we would clamp
it to a literal zero. If that element also had a flex-basis 0
it's width would end up being 0.
This patch adds a determine_min_main_size_of_child function that
will calculate the minimum main size for the box based on the
content of the box.
We use the result of that function now instead of clamping
the element main min size to 0.

This also adds one more box to the flex.html test page, which is
the same flex: 0 0 0 box but with flex-direction: column.
2022-03-30 21:16:47 +02:00
Enver Balalic
4ecc695a65 LibWeb: Take borders and padding into account when doing Flex layout
Before this the flex layout didn't take into account the applied
borders or padding while laying out the items.

The child's top and left borders would get painted over the
parent's borders, also due to it not taking borders into account,
children with borders would overlap each other.

Due to it not taking padding into account, the children would get
drawn outside the parent element.
2022-03-27 17:43:47 +02:00
Andreas Kling
2e6f5fddef LibWeb: Transfer flex item box model metrics to paintable
Until now, flex items has 0/0/0 margin/border/padding values.
2022-03-26 17:31:01 +01:00
Johannes Laudenberg
eb1d7e8076 LibWeb: Make margins in the main dimension work for flex items
The spec at https://www.w3.org/TR/css-flexbox-1/ states that when
calculating specific spaces and sizes inside a flex container, the outer
size of a flex item needs to be taken into account.

This patch adds the margins in the main dimension of a flex item to
these calculations such that their margins are actually painted in a lot
of common cases.

It makes our Github page look marginally better.
2022-03-23 11:59:07 +01:00
Andreas Kling
c1f0d21bbe LibWeb: Rename the LayoutMode enum values and explain them
The old mode names, while mechanically accurate, didn't really reflect
their relationship to the CSS specifications.

This patch renames them as follows:

    Default => Normal
    AllPossibleLineBreaks => MinContent
    OnlyRequiredLineBreaks => MaxContent

There's also now an explainer comment with the LayoutMode enum about the
specific implications of layout in each mode.
2022-03-19 15:46:15 +01:00
Andreas Kling
8d5768b103 LibWeb: Don't treat inline-level children of flex items as whitespace
This was causing us to collapse some children of flex items as if they
were useless whitespace text nodes.
2022-03-19 12:42:10 +01:00
Lenny Maiorani
c37820b898 Libraries: Use default constructors/destructors in LibWeb
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#cother-other-default-operation-rules

"The compiler is more likely to get the default semantics right and
you cannot implement these functions better than the compiler."
2022-03-17 17:23:49 +00:00
Andreas Kling
ab9d9709b9 LibWeb: Give flex containers with percentage cross size some dimensions
Instead of making them zero-sized on the cross axis, just treat
percentage sizes like auto for now. Better to have *some* size than none
at all.
2022-03-13 00:04:51 +01:00
Andreas Kling
bd94f2c4c8 LibWeb: Add a debug helper to dump current state of an FFC 2022-03-13 00:04:51 +01:00
Andreas Kling
ad8d65fd6e LibWeb: Fix calculation of hypothetical cross size in column flex layout
Simplify automatic cross sizing of items in flex-direction:column by
using the fit-content width directly.

There's obviously a lot more nuance to this, but for now this makes
flex items with both width:auto and height:auto actually get some height
in column flex layouts.
2022-03-13 00:04:51 +01:00
Andreas Kling
515db5fc1b LibWeb: Make Layout::FormattingState copies shallow
Previously, each NodeState in a FormattingState was shared with the
parent FormattingState, but the HashMap of NodeState had to be copied
when making FormattingState copies.

This patch makes copying instant by keeping a pointer to the parent
FormattingState instead. When fetching immutable state via get(), we may
now return a reference to a NodeState owned by a parent FormattingState.

get_mutable() will copy any NodeState found in the ancestor chain before
making a brand new one.
2022-03-13 00:04:51 +01:00
Andreas Kling
8c91e8016c LibWeb: Handle many more cases with intrinsic/auto sizing in flex layout
The flexbox specification barely even handwaves about automatically
sized items, but there's actually a lot of work to do in order for them
to get the correct size.

This patch is messy, but does make significant progress on supporting
flex items with indefinite width and/or height.

There's a fair amount of nested layout going on here, but do note that
we'll be hitting the intrinsic sizes cache whenever possible.
2022-03-13 00:04:51 +01:00
Andreas Kling
e4eb6d4f1f LibWeb: Add FFC helpers for resolving definite main/cross sizes
Although something has a definite size, we may still have to "resolve"
it, since FFC is quite liberal in what it considers to be definite.

Let's put that logic in a set of helper functions.
2022-03-13 00:04:51 +01:00
Andreas Kling
5c8e7217f7 LibWeb: Remove ad-hoc setup step from FFC layout algorithm
This step will not be necessary when we implement indefinite size
calculations more correctly.
2022-03-13 00:04:51 +01:00
Andreas Kling
43b8f65d82 LibWeb: Support indefinite flex container cross sizes
Instead of assuming that any indefinite cross size must be "auto", check
what is actually is, and resolve it accordingly.
2022-03-13 00:04:51 +01:00
Andreas Kling
a3a10b2379 LibWeb: Fix flex line alignment in single-line flex containers
For single-line flex containers, center the only flex line along the
cross axis. Alignment of multi-line flex containers are left as a FIXME.

This patch also moves out the assignment of final metrics to the
FormattingState from align_all_flex_lines() to a separate function.
2022-03-13 00:04:51 +01:00
Andreas Kling
1dfb3d555c LibWeb: Remove FFC::cross_size_is_absolute_or_resolved_nicely()
This is now answered authoritatively by Layout::Box itself.
2022-03-13 00:04:51 +01:00
Andreas Kling
1ce1af5d8b LibWeb: Improve FFC step 7 (hypothetical cross size)
- Avoid performing inside layout on definite-size flex items (since
  their computed size can be used as-is.)

- Use FormattingState::clone() to generate a throwaway layout instead of
  mutating the tree in-place.

- Update spec link & comments based on current CSSWG draft. The latest
  version is quite a bit clearer on how this should work.
2022-03-13 00:04:51 +01:00
Andreas Kling
b904bff838 LibWeb: Put available space information in an FFC member
This makes it easier for each step of the flex layout algorithm to
access this information.
2022-03-13 00:04:51 +01:00
Andreas Kling
88302b0dca LibWeb: Layout inside of flex items at the end of FFC layout
Instead of doing internal child layout incrementally as we go, save it
for the end of flex layout. The code will become simpler if we can focus
on simply computing the dimensions of each flex item while we're doing
the main FFC algorithm.
2022-03-13 00:04:51 +01:00
Andreas Kling
7c5b578df9 LibWeb: Move unrelated things out of FFC step 1
Setting some initial width and height on the flex container is totally
unrelated to the "generate anonymous flex items" step.
2022-03-13 00:04:51 +01:00
Andreas Kling
3506a91349 LibWeb: Avoid unnecessary layout_inside() in FFC step 1
We don't need to perform inside layout here. The only information we
need in this step is whether an anonymous block container has nothing
but empty-or-whitespace text children.

This information is already accurate after the initial layout tree
construction. Performing a layout does not change the answer. It does
however have many other side effects, so let's defer those.
2022-03-13 00:04:51 +01:00
Andreas Kling
db5bf6e64c LibWeb: Rename FormattingState::ensure() -> get_mutable()
This makes it much more obvious what the difference between get() and
get_mutable() is.
2022-02-21 18:35:12 +01:00
Andreas Kling
c9700e100e LibWeb: Start making our layout system "transactional"
This patch adds a map of Layout::Node to FormattingState::NodeState.
Instead of updating layout nodes incrementally as layout progresses
through the formatting contexts, all updates are now written to the
corresponding NodeState instead.

At the end of layout, FormattingState::commit() is called, which
transfers all the values from the NodeState objects to the Node.

This will soon allow us to perform completely non-destructive layouts
which don't affect the tree.

Note that there are many imperfections here, and still many places
where we assign to the NodeState, but later read directly from the Node
instead. I'm just committing at this stage to make subsequent diffs
easier to understand.
2022-02-21 18:35:12 +01:00
Andreas Kling
561612f219 LibWeb: Add Layout::FormattingState
The purpose of this new object will be to keep track of various states
during an ongoing layout.

Until now, we've been updating layout tree nodes as we go during layout,
which adds an invisible layer of implicit serialization to the whole
layout system.

My idea with FormattingState is that running layout will produce a
result entirely contained within the FormattingState object. At the end
of layout, it can then be applied to the layout tree, or simply queried
for some metrics we were trying to determine.

When doing subtree layouts to determine intrinsic sizes, we will
eventually be able to clone the current FormattingState, and run the
subtree layout in isolation, opening up opportunities for parallelism.

This first patch doesn't go very far though, it merely adds the object
as a skeleton class, and makes sure the root BFC has one. :^)
2022-02-21 18:35:12 +01:00
Andreas Kling
c04c2df0f7 LibWeb: Add missing is_length() check in FFC::is_cross_auto()
We can't access LengthPercentage::length() before verifying that it's
indeed a length.
2022-02-18 19:19:56 +01:00
Sam Atkins
356d8bcfe8 LibWeb: Remove Length::Type::Undefined! :^) 2022-02-18 19:04:37 +01:00
Sam Atkins
b715943035 LibWeb: Remove redundant Length::resolved() calls
Now that calc() is also resolved in to_px(), code in the form
`foo.resolved(bar).to_px(bar)` can be simplified to `foo.to_px(bar)`.
2022-02-18 19:04:37 +01:00
Sam Atkins
67066c5140 LibWeb: Remove fallback value from Length::resolved()
Nobody makes undefined Lengths now, (although actually removing
Undefined will come in a later commit) so we can remove this parameter,
and `resolved_or_auto()`/`resolved_or_zero()`.
2022-02-18 19:04:37 +01:00
Sam Atkins
5b2482a939 LibWeb: Use Optional instead of undefined-lengths for widths/heights 2022-02-18 19:04:37 +01:00
Andreas Kling
0608de8c12 LibWeb: Rename Layout::Box::size() to content_size()
This property represents the CSS content size, so let's reduce ambiguity
by using the spec terminology.

We also bring a bunch of related functions along for the ride.
2022-02-06 01:07:47 +01:00
Sam Atkins
ce0de4b2b4 LibWeb: Allow LengthPercentage to hold a calculated value
Most of the time, we cannot resolve a `calc()` expression until we go to
use it. Since any `<length-percentage>` can legally be a `calc
()`, let's store it in `LengthPercentage` rather than make every single
user care about this distinction.
2022-02-04 13:52:02 +01:00
Andreas Kling
00bd17034d LibWeb: Make IFC aware that its parent is always a BFC
This simplifies some code and allows us to use tighter types for the
parent context everywhere.
2022-01-24 02:09:17 +01:00
Sam Atkins
bfcbab0dcf LibWeb: Remove reference_for_percent parameter from Length::resolved()
Despite looking like it was still needed, it was only used for passing
to other calls to Length::resolved() recursively. This makes the
various `foo.resolved().resolved()` calls a lot less awkward.
(Though, still quite awkward.)

I think we'd need to separate calculated lengths out to properly tidy
these calls up, but one yak at a time. :^)
2022-01-20 00:04:10 +01:00
Sam Atkins
dc681913e8 LibWeb: Convert width/height and min-/max- versions to LengthPercentage
A lot of this is quite ugly, but it should only be so until I remove
Length::Type::Percentage entirely. (Which should happen later in this
PR, otherwise, yell at me!) For now, a lot of things have to be
resolved twice, first from a LengthPercentage to a Length, and then
from a Length to a pixel one.
2022-01-20 00:04:10 +01:00
Sam Atkins
cb0cce5cdc LibWeb: Convert flex-basis to LengthPercentage
The flexbox logic confuses me so regressions are possible, though our
test page looks the same as before so it should be fine.

Renamed FlexBasis::Length -> LengthPercentage too, for clarity.
2022-01-20 00:04:10 +01:00
Sam Atkins
7196570f9b LibWeb: Cast unused smart-pointer return values to void 2021-12-05 15:31:03 +01:00
Andreas Kling
ca154723f7 LibWeb: Remove Layout::Box::width_of_logical_containing_block()
This was a hack to percentages within tables relative to the nearest
table-row ancestor instead of the nearest table container.

That didn't actually make sense, so this patch simply removes the hack
in favor of containing_block()->width().
2021-10-27 18:00:51 +02:00
Andreas Kling
c1ba9c66b5 LibWeb: Use is_single_line() and add spec comments to FFC step 8 2021-10-21 16:48:24 +02:00
Andreas Kling
07f15aa550 LibWeb: Make computed flex-grow and flex-shrink always available
These values are not allowed to be absent (auto/none/etc) so we don't
need to use Optional<float> for them. This simplifies some things.
2021-10-19 19:17:01 +02:00
Andreas Kling
f2d0e8d0ee LibWeb: Expose FormattingContext type
Instead of having a virtual is_block_formatting_context(), let's have a
type() that can tell you exactly which type of formatting context it is.
2021-10-17 22:18:59 +02:00
Andreas Kling
410e2b43ce LibWeb: Use Box::has_intrinsic_aspect_ratio() check in FFC step 3
Now that we can ask any Box about its intrinsic aspect ratio, let's fix
a FIXME in FlexFormattingContext.
2021-10-14 19:42:09 +02:00