When drawing a table, some of the CSS properties must be moved from the
table grid box to an anonamyous table wrapper box. One of these
properties is `position`. `z-index` however is not. This leads to the
following behavior if a table has both `position` and `z-index`:
* The wrapper box has the `position`, but a `z-index` of `auto`.
* The grid box has the `z-index`, but `position: static`.
This effectively means that the `z-index property is ignored since it
has no effect on non-positioned elements. This behavior contradicts what
other browsers do and causes layout issues on websites.
To align Ladybird behavior with other browser this commit also moves the
`z-index` property to the wrapper box.
This was an old hack intended to make percentage sizes on flex items
before we had implemented the appropriate special behavior of definite
sizes in flex layout.
Removing it makes flex layout less magical and should not change
behavior in any observable way.
The spec tells us to treat `auto` as `fit-content` when determining
flex item cross sizes, so let's just do *that* instead of awkwardly
doing an uncacheable nested layout of the item.
This was the only instance of `LayoutState` nesting outside of intrinsic
sizing, so removing it is an important step towards simplifying layout.
Turns out it was a lot easier than expected.
We've long claimed to support this, but then silently ignored string
values, until 4cb2063577 which would
not-so-silently crash instead. (Oops)
So, actually pass the string value along and use it in the list marker.
As part of this, rename our `list-style-type` enum to
`counter-style-name-keyword`. This is an awkward name, attempting to be
spec-based. (The spec says `<counter-style>`, which is either a
`<counter-style-name>` or a function, and the `<counter-style-name>` is
a `<custom-ident>` that also has a few predefined values. So this is the
best I could come up with.)
Unfortunately only one WPT test for this passes - the others fail
because we produce a different layout when text is in `::before` than
when it's in `::marker`, and similar issues.
This was an old hack from before we understood how and when to resolve
percentages in flex layout. Removing it should not change anything,
but it does avoid a lot of redundant layout work on many pages.
At computed-value time, this is converted to whatever the parent's
computed value is. So it behaves a little like `inherit`, except that
an inherited start/end value uses the parent's start/end, which might
be different from the child's.
We've historically asserted that no "saturated" size values end up as
final metrics for boxes in layout. This always had a chance of producing
false positives, since you can trivially create extremely large boxes
with CSS.
The reason we had those assertions was to catch bugs in our own engine
code where we'd incorrectly end up with non-finite values in layout
algorithms. At this point, we've found and fixed all known bugs of that
nature, and what remains are a bunch of false positives on pages that
create very large scrollable areas, iframes etc.
So, let's change it! We now clamp content width and height of boxes to
17895700 pixels, apparently the same cap as Firefox uses.
There's also the issue of calc() being able to produce non-finite
values. Note that we don't clamp the result of calc() directly, but
instead just clamp values when assigning them to content sizes.
Fixes#645.
Fixes#1236.
Fixes#1249.
Fixes#1908.
Fixes#3057.
While keyword_to_foo() does return Optional<Foo>, in practice the
invalid keywords get rejected at parse-time, so we don't have to worry
about them here. This simplifies the user code quite a bit.
This fixes the very, _very_ slow loading of https://yzy-sply.com. The
`apply_style()` method also calls into this method recursively, so we
just need to call it once instead of once per node in the continuation
chain.
This was mainly a matter of deferring the wrapping of the button's
children until after its internal layout tree has been constructed.
That way we don't lose any pseudo elements spawned along the way.
Fixes#2397.
Fixes#2399.
To be properly compatible with calc(), the resolved() methods all need:
- A length resolution context
- To return an Optional, as the calculation might not be resolvable
A bonus of this is that we can get rid of the overloads of `resolved()`
as they now all behave the same way.
A downside is a scattering of `value_or()` wherever these are used. It
might be the case that all unresolvable calculations have been rejected
before this point, but I'm not confident, and so I'll leave it like
this for now.
Initially I added this to the existing CalculationContext, but in
reality, we have some data at parse-time and different data at
resolve-time, so it made more sense to keep those separate.
Instead of needing a variety of methods for resolving a Foo, depending
on whether we have a Layout::Node available, or a percentage basis, or
a length resolution context... put those in a
CalculationResolutionContext, and just pass that one thing to these
methods. This also removes the need for separate resolve_*_percentage()
methods, because we can just pass the percentage basis in to the regular
resolve_foo() method.
This also corrects the issue that *any* calculation may need to resolve
lengths, but we previously only passed a length resolution context to
specific types in some situations. Now, they can all have one available,
though it's up to the caller to provide it.
BFC roots behave differently in that their height is computed twice,
before and after inside layout, since automatic height depends on the
results of inside layout. Other formatting contexts only require the
"before" pass, and so we can treat their content sizes as definite
before proceeding with inside layout.
This makes https://play.tailwind.com/ look beautiful. :^)
When positioning floats against an edge, we are taking all current
relevant floats at that side into account to determine the Y offset at
which to place the new float. However, we were using the margin box
height instead of the absolute bottom position, which disregards the
current float's Y-position within the root, and we were setting the Y
offset to that height, instead of taking the new float's Y position
inside of the root into account.
The new code determines the lowest margin bottom value within the root
of the current floats, and adds the difference between that value and
the new float's Y position to the Y offset.
I see no good reason to keep them out of line, and having the methods
named differently than the property they're updating caused me some
confusion initially.
Our layout tree requires that all containers either have inline or
non-inline children. In order to support the layout of non-inline
elements inside inline elements, we need to do a bit of tree
restructuring. It effectively simulates temporarily closing all inline
nodes, appending the block element, and resumes appending to the last
open inline node.
The acid1.txt expectation needed to be updated to reflect the fact that
we now hoist its <p> elements out of the inline <form> they were in.
Visually, the before and after situations for acid1.html are identical.
The existing `::unite_horizontally()` and `::unite_vertically()` tests
did not properly test the edge cases where left/top in the Rect were
updated, so they get re-arranged a bit.
When an element is displayed as table, an anonymous table wrapper box
needs to be created for it. Among others, the position property of the
table element is then applied to the anonymous table wrapper box
instead. If the table happens to be positioned absolutely, the table
wrapper box may become the containing block for absolutely positioned
elements inside the table.
In the original code however, anonymous layout nodes were excluded from
becoming the containing block for an absolutely positioned element.
Because of this, the containing block was calculated to be the first
suitable parent block of the table wrapper box.
This incorrect containing block would result in a crash later on when
trying to size the absolutely positioned element inside the table. To
prevent this crash, the anonymous table wrapper box is now allowed to
become the containing block for absolutely positioned elements inside
a table.
The definition of containing block for an absolutely positioned element
in the spec does not mention anything about skipping anonymous boxes.
Additionally the rules for absolute positioning of tables
(https://www.w3.org/TR/css-tables-3/#abspos-boxes-in-table-root) imply
that a table wrapper box is indeed able to be the containing block for
absolutely positioned elements.
DOM nodes now have two additional flags:
- Needs layout tree update
- Child needs layout tree update
These work similarly to the needs-style-update flags, but instead signal
the need to rebuild the corresponding part of the layout tree.
When a specific DOM node needs a layout tree update, we try to create
a new subtree starting at that node, and then replace the subtree in the
old layout tree with the newly created subtree.
This required some refactoring in TreeBuilder so that we can skip over
entire subtrees during a tree update.
Note that no partial updates happen yet (as of this commit) since we
always invalidate the full layout tree still. That will change in the
next commit.
Instead just update the existing wrapper with computed values from the
table box, to insure that upside-down "inheritance" works as expected.
This allows table fixup to run on partially updated layout trees without
adding a new layer of unnecessary wrappers every time.
Same again, although rotation is more complicated: `rotate`
is "equivalent to" multiple different transform function depending on
its arguments. So we can parse as one of those instead of the full
`rotate3d()`, but then need to handle this when serializing.
This improves the quality of our font rendering, especially when
animations are involved. Relevant changes:
* Skia fonts have their subpixel flag set, which means that individual
glyphs are rendered at subpixel offsets causing glyph runs as a
whole to look better.
* Fragment offsets are no longer rounded to whole device pixels, and
instead the floating point offset is kept. This allows us to pass
through the floating point baseline position all the way to the Skia
calls, which already expected that to be a float position.
The `scrollable-contains-table.html` ref test needed different table
headings since they would slightly inflate the column size in the test
file, but not the reference.
This reverts commit 76daba3069.
We're going to need separate types for the JS-exposed style values, so
it doesn't make sense for us to match their names with our internal
types.
CSS filters work similarly to canvas filters, so it makes sense to have
Gfx::Filter that can be used by both libraries in an analogous way
as Gfx::Color.