Commit graph

110 commits

Author SHA1 Message Date
Jelle Raaijmakers
ab3e9799d5 LibWeb: Allow negative margins to influence inline offset after float
In 89ba00304c, the box' X position was
capped at 0 to prevent negative X positions to act as if there were
intruding floats on the left side. Instead, we need to check whether the
left side float intrusion we are going to calculate matters at all -
because if there's no matching float box, the intrusion is always going
to be 0 and we don't need to take the box' X position into account.

Fixes the floating publication images on https://lexfridman.com/.
2025-07-28 12:11:56 +02:00
Andreas Kling
8d02f28cc2 LibWeb: Don't treat non-replaced sizes as 0 for min-content contrib
This behavior is part of the cyclic percentage contribution logic from
CSS-SIZING-3 which explicitly only applies to non-replaced boxes.

This fixes an issue on Discord where buttons in the settings UI were
cropped to a narrower width than intended.

Fixes #3572
2025-07-23 19:52:59 +02:00
Andreas Kling
11fa5fdd47 LibWeb: Honor box-sizing for block-level replaced element widths
Before this change, we were always behaving as if box-sizing were
content-box for block-level replaced element widths.

This fixes the squishy logo on https://videolan.org/
2025-07-14 11:16:13 +02:00
Psychpsyo
c0e44820e9 Tests: Add doctypes to remaining test cases 2025-06-21 14:09:47 +02:00
Jelle Raaijmakers
30efcd0d00 LibWeb: Prevent time-traveling leading inline metrics
Some checks are pending
CI / macOS, arm64, Sanitizer_CI, Clang (push) Waiting to run
CI / Linux, x86_64, Fuzzers_CI, Clang (push) Waiting to run
CI / Linux, x86_64, Sanitizer_CI, GNU (push) Waiting to run
CI / Linux, x86_64, Sanitizer_CI, Clang (push) Waiting to run
Package the js repl as a binary artifact / macOS, arm64 (push) Waiting to run
Package the js repl as a binary artifact / Linux, x86_64 (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
In `InlineLevelIterator`, whenever we call `skip_to_next()` and enter a
node with box model metrics, we could potentially accumulate leading and
trailing metrics. This lead to a weird situation where an element with
`display: inline-block` could adopt the leading metrics of an inline
element that follows it, since we perform the call to
`add_extra_box_model_metrics_to_item()` too late.

Move `skip_to_next()` down so it no longer interferes with the `Item`
we're creating.

The test expectation for
`atomic-inline-with-percentage-vertical-align.html` is updated, although
neither the old nor new results are 100% accurate since either box jumps
one pixel to the right.
2025-06-20 19:59:32 +02:00
Ruben
3263b629c6 LibWeb: Correct the calculation for right float intrusion
We used to subtract the maximum right margin of any containing box,
but we want to subtract the entire right margin instead. This yielded
incorrect intrusions for right floats not placed in the root.
2025-05-27 17:31:47 +02:00
Aziz Berkay Yesilyurt
6711438e0d LibWeb: Ensure anonymous wrappers inherit inline-block display
When restructuring a block node inside an inline parent, if the
nearest block ancestor is `display: inline-block`, ensure that
the generated anonymous wrappers also have `display: inline-block`.
This fixes layout issues with block elements nested
inside inline-block elements.
2025-05-23 11:16:06 +02:00
Ruben
09f5ce42f6 LibWeb: Ensure floats are correctly placed under the preceding float
Previously floats would be placed next to the highest float that
fitted the new float on its line. However, this violates the rule
that floats should be placed under the preceding float if it does
not fit next to it.
2025-05-23 10:58:15 +02:00
Jelle Raaijmakers
170e599bd9 LibWeb: Always set the Y offset of the current block in BFC
Originally part of a fix in 15103d172c, it
appears that this is no longer necessary and received a better fix in a
more recent commit. Resolves a visual regression with the ACID3 test.
2025-05-16 20:33:27 +02:00
Jelle Raaijmakers
123abe0e79 LibWeb: Overlap float space and left margins for all shared ancestors
Some checks are pending
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (arm64, macos-15, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (x86_64, ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
We would only correct for the left margin of the containing block of the
child box that we are laying out, but we actually need to correct for
all left margins up until the containing block that contains both the
float and the child box.

Fixes #4639.
2025-05-09 14:13:02 +02:00
Jelle Raaijmakers
6f800caeaa LibWeb: Don't mess up the order of nodes when wrapping inline contents
Whenever we introduce a block element in a container that at that point
has only had inline children, we create an anonymous wrapper for all the
inline elements so we can keep the invariant that each container
contains either inline or non-inline children. For some reason, we
ignore all the out-of-flow nodes since they are layed out separately and
it was thought that this shouldn't matter.

However, if we are dealing with inline blocks and floating blocks, the
order of the inline contents _including_ out-of-flow nodes becomes very
important: floating blocks need to take the order of nodes into account
when positioning themselves.

Fix this by simply hoisting the out-of-flow nodes into the anonymous
wrapper as well.

Fixes the order of blocks in #4212. The gap is still not present.
2025-04-24 19:12:50 +02:00
Jelle Raaijmakers
79352ad725 LibWeb: Remove application of vertical float clearance to BFC Y offset
In 15103d172c we applied any remaining vertical float clearance to the
BFC's current Y offset for the next block to layout, because a `<br
style="clear: left">` could introduce clearance that would otherwise be
ignored. However, a `<div>` that floats _and_ clears `right` also
introduces this clearance and it is obvious that this should not push
down any subsequent blocks to layout in the current BFC.

Turns out, we don't need this change anymore. Some other later change
also fixed the underlying issue, and by getting rid of the original fix
we can now render https://en.wikipedia.org/wiki/SerenityOS correctly
again.

Fixes #4418.
2025-04-23 13:24:58 +02:00
Jelle Raaijmakers
8257788a20 LibWeb: Ignore negative margins for margin box rect
Some checks are pending
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (arm64, macos-15, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (x86_64, ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
Negative margins are processed through the `offset` in layout state, and
should not contribute to the margin box' rect's size or position.

Fixes #4249.
2025-04-11 02:34:28 +01:00
Jelle Raaijmakers
99df80f81e LibWeb: Only apply box offset if the box is not already the ancestor
When determining the content/margin box rects within their ancestor's
coordinate space, we were returning early if the passed in values
already belonged to the requested ancestor. Unfortunately, we had
already applied the used values' offset to the rect, which is the offset
to the ancestor's ancestor.

This simplifies the logic to always apply the rect offset after checking
if we've reached the ancestor. Fixes determining float intrusions inside
block elements with `margin: auto` set.

Fixes #4083.
2025-04-04 15:35:26 +02:00
Jelle Raaijmakers
6d911a6baa LibWeb: Resolve block height correctly after line break with clear: ..
If a block with inline children ends with a line break clearing any
floats, we not only need to take the introduced clearance into account
for the next line box, but the containing block needs to set the correct
height as well.

Since the spec calls for using the last line box' bottom as the resolved
height (if treated as auto), we now correctly apply the clearance to the
previous line box' bottom coordinate.

Fixes #4058.
2025-04-01 16:02:53 +02:00
Jelle Raaijmakers
45905d6f7b LibWeb: Use relative coordinates for available_space_for_line()
We were accidentally providing it with absolute Y-coordinates, messing
up stacked floating boxes that would otherwise intrude on each other.

Fixes #4160.
2025-04-01 15:26:12 +02:00
Jelle Raaijmakers
04ba375cc7 LibWeb: Only set line builder's block offset if clearance increases it
This prevents text from overlapping with each other if a `<br>` with
`clear: ..` is used in between.
2025-03-31 08:11:10 +01:00
Aliaksandr Kalenik
732a5cdc12 LibWeb: Respect min/max-content available size in auto width calculation
Some checks are pending
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
...for block level boxes. Otherwise we end up resolving auto width as
zero during intrinsic layout, which leads to incorrectly applied
max-width constraint.

Fixes https://github.com/LadybirdBrowser/ladybird/issues/4123
2025-03-28 02:13:41 +00:00
Aliaksandr Kalenik
fc45121b70 LibWeb: Size box as normal if it has aspect ratio but auto sizes
Otherwise we apply `calculate_stretch_fit_width()` instead of
calculating width based on the content inside the box, like other
browsers do.
2025-03-27 23:13:57 +00:00
Jelle Raaijmakers
15103d172c LibWeb: Apply remaining vertical float clearance to next block level box
Whenever we generate line boxes, we might end up with a residual
vertical float clearance by way of having a `<br>` with `clear: ..` set.
Set the Y offset of the next block level box to place by this vertical
clearance.

Relates to #4058.
2025-03-27 17:21:56 +00:00
Jelle Raaijmakers
683d6b77dd LibWeb: Apply vertical clearance to next line after <br> with clear:
We were introducing a line break and applying vertical clearance to the
inline formatting context, but that vertical clearance only applied to
new floating boxes. We should move the current block offset to the
vertical clearance to make sure the next line box starts beyond the
cleared floats.

There was a layout test for `<br>` with `clear: ..` set, but that test
did not actually do anything - removing the `clear` property would
result in the same layout. Replace that test with something that
actually tests float clearing.

Relates to #4058.
2025-03-27 13:57:59 +00:00
Jelle Raaijmakers
c4bb74f40b LibWeb: Fix and improve float positioning behavior
Our recent change to get rid of the "move 1px at a time" algorithm in
the float positioning logic introduced the issue that potentially
intersecting float boxes were not evaluated in order anymore. This could
result in float boxes being pushed down further than strictly necessary.

By finding the highest point we can move the floating box to and
repeating the process until we're no longer intersecting any floating
box, we also solve some edge cases like intersecting with very long
floating boxes whose edges lay outside the current box' edges.

This is by no means the most efficient solution, but it is more correct
than what we had until now.

Fixes #4110.
2025-03-27 10:56:13 +00:00
Jelle Raaijmakers
f340f8682b LibWeb: Do not clear float sides for floating boxes with clear: ..
Some checks are pending
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
We used to always clear the side data after encountering a box with
`clear: ..`, but this is not the right thing to do if that same box also
has `float: ..` set. For example, with `clear: right` and `float: left`
it might be that the next box still wants to clear the right side, and
since the previous box is floating it did not push the next box down far
enough to justify clearing the side data at that point.

This changes the logic to only clear the float side if the clearing box
itself is not floating. We also no longer clear the opposite side after
placing a floating box; that doesn't seem to be necessary anymore.

Fixes #4102.
2025-03-27 00:56:56 +00:00
Jelle Raaijmakers
002e79a658 LibWeb: Exclude trailing whitespace from line width when placing floats
When generating line boxes, we place floats simultaneously with the
other items on the same line. The CSS text spec requires us to trim the
whitespace at the end of each line, but we only did so after laying out
all the line boxes.

This changes the way we calculate the current line box width for floats
by subtracting the amount of pixels that the current trailing whitespace
is using.

Fixes #4050.
2025-03-26 19:35:38 +00:00
Aliaksandr Kalenik
275985ff3d LibWeb: Ignore non-box element while collecting abspos nodes for layout
All abspos boxes are expected to be blockified, so we are certain that
we can ignore non-box elements when collecting abspos nodes for layout.

Fixes a crash caused by an attempt to cast a BreakNode to a Box while
performing abspos layout.
2025-03-26 00:17:53 +00:00
Aliaksandr Kalenik
c49dd2036b LibWeb: Mark height as definite before doing inner layout of abspos
...boxes with non-auto height.

We know for sure that by the time we layout abspos boxes, their
containing block has definite height, so it's possible to resolve
non-auto heights and mark it as definite before doing inner layout.

Big step towards having reasonable performance on
https://demo.immich.app/photos because now we avoid a bunch of work
initiated by mistakenly invoked intersection observer callbacks.

Co-Authored-By: Andreas Kling <andreas@ladybird.org>
2025-03-21 14:46:31 -05:00
Aliaksandr Kalenik
227b4c38b7 LibWeb: Use parent's available space for anonymous blocks in BFC
Height resolution assumes that when available space is definite, it
matches the size of non-anonymous containing block. With this change, we
correctly maintain this assumption when box is wrapped in anonymous
node.

Fixes https://github.com/LadybirdBrowser/ladybird/issues/3422
2025-03-15 13:31:07 +01:00
Andreas Kling
16662ab230 LibWeb: Account for collapsed top margins in BFC root height calculation
By the time we're measuring the height of a BFC root, we've already
collapsed all relevant margins for the root and its descendants.
Given this, we should simply use 0 (relative to the BFC root) as the
lowest block axis coordinate (i.e Y value) for the margin edges.

This fixes a long-standing issue where BFC roots were sometimes not tall
enough to contain their children due to margins.
2025-02-22 18:41:42 +01:00
Jelle Raaijmakers
e8bc6e9e8e LibWeb: Set float Y offset using margin box bottom instead of height
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.
2025-01-28 01:12:23 +01:00
Aliaksandr Kalenik
3a5e78780e LibWeb: Implement "The percentage height calculation quirk" in BFC
See https://quirks.spec.whatwg.org/#the-percentage-height-calculation-quirk

Basically, it means that in quirks mode, percentage height needs to be
resolved against nearest ancestor in the containing block chain that
does not have height=auto.

Fixes https://github.com/LadybirdBrowser/ladybird/issues/365
2024-09-28 14:41:26 +02:00
Aliaksandr Kalenik
9098e39a43 LibWeb: Resolve not auto height before child box layout in BFC
It's possible to resolve box's height without doing inner layout, when
computed value is not auto. Doing that fixes height resolution, when box
with percentage height has containing block with percentage height.

Before:
- resolve used width
- layout box's content
- resolve height

After:
- resolve used width
- resolve height if treated as not auto
- layout box's content
- resolve height if treated as auto
2024-09-27 20:25:25 +02:00
Pavel Panchekha
9075f64cac LibWeb: Change inline float clearance to not reset margin collapsing
When a block container has `clear` set and some clearance is applied,
that clearance prevents margins from adjoining and therefore resets
the margin state. But when a floating box has `clear` set, that
clearance only goes between floating boxes so should not reset margin
state. BlockFormattingContexts already do that correctly, and this PR
changes InlineFormattingContext to do the same.

Fixes #1462; adds reduced input from that issue as test.
2024-09-21 01:55:43 +02:00
Aliaksandr Kalenik
e3e0041c7f Tests/LibWeb: Add layout test for float box with box-sizing=border-box
Adds a test for d6a31d80c0 that was
mistakenly ommited in the first place.
2024-09-18 15:49:40 +02:00
Aliaksandr Kalenik
5f74da6ae8 LibWeb: Fix "box-sizing: border-box" resolution for abspos items
The `calculate_inner_width()` and `calculate_inner_height()` resolve
percentage paddings using the width returned by
`containing_block_width_for()`. However, this function does not account
for grids where the containing block is defined by the grid area to
which an item belongs.

This change fixes the issue by modifying `calculate_inner_width()` and
`calculate_inner_height()` to use the already resolved paddings from the
layout state. Corresponding changes ensure that paddings are resolved
and saved in the state before box-sizing is handled.

As a side effect, this change also improves abspos layout for BFC where
now paddings are resolved using padding box of containing block instead
of content box of containing block.
2024-09-17 07:56:18 +02:00
Andreas Kling
c22acc2551 LibWeb: Implement vertical-align: middle correctly for atomic inlines
This makes inline icons pop into the right place on https://ahrefs.com/
2024-08-26 15:49:07 +02:00
Aliaksandr Kalenik
0be57df54d LibWeb: Subtract left inset from size_available_for_margins for abspos
Fixes https://github.com/LadybirdBrowser/ladybird/issues/712
2024-07-19 13:29:20 +01:00
Colin Reeder
d427344f39 LibWeb: Handle inline-start and inline-end as float values
Should resolve #449 for LTR languages at least
2024-07-10 17:41:18 +02:00
Arthur Hartwig Carlsson
9ed2669fc8 LibWeb: Don't insert out-of-flow elements into block pseudo elements
Like 1132c858e9, out-of-flow elements such
as float elements would get inserted into block level `::before` and
`::after` pseudo-element nodes when they should instead be inserted as a
sibling to the pseudo element. This change fixes that.

This fixes a few layout issues on the swedish tax agency website
(skatteverket.se). :^)
2024-07-06 10:02:29 +02:00
Andreas Kling
d37c0a2cab LibWeb: Don't make flex layout responsible for flex container cross size
Although the flex algorithm as specified does say to determine the cross
size of the flex container, this is not how our layout engine works.

The parent formatting context is responsible for sizing its children,
and since that's already happening, we can simply remove the cross
sizing step from FFC.
2024-03-27 16:43:04 +01:00
Tim Ledbetter
99fbd33d7d LibWeb: Make button flex wrapper inherit min-height property
This ensures that the vertical positioning of button text is correct
if a `min-height` property is present.
2024-01-28 14:48:33 +01:00
Andreas Kling
1041dbb007 LibWeb: Don't lose track of inline margins when collapsing whitespace
When iterating inline level chunks for a piece of text like " hello ",
we will get three separate items from InlineLevelIterator:

- Text " "
- Text "hello"
- Text " "

If the first item also had some leading margin (e.g margin-left: 10px)
we would lose that information when deciding that the whitespace is
collapsible.

This patch fixes the issue by accumulating the amount of leading margin
present in any collapsed whitespace items, and then adding them to the
next non-whitespace item in IFC.

It's a wee bit hackish, but so is the rest of the leading/trailing
margin mechanism.

This makes the header menu on https://www.gimp.org/ look proper. :^)
2024-01-20 23:29:51 +01:00
Aliaksandr Kalenik
e7eaf3b566 LibWeb: Remove rounding division for CSSPixels
Reverts 98926b487c
that regressed: block-and-inline/small-percentage-margin.html
(thrashing layout while window resizing)

Fixes https://github.com/SerenityOS/serenity/issues/22610
2024-01-06 21:40:27 +01:00
Aliaksandr Kalenik
b172c29d9a LibWeb: Apply min/max-widths to block container during intrinsic layout
Fixes https://github.com/SerenityOS/serenity/issues/22430
2023-12-26 16:24:51 +01:00
Andreas Kling
7abb182fa3 LibWeb: Honor negative margins on atomic inlines
Sizing already worked correctly, but before this change, we were too
aggressive with inserting line breaks when negative margins would
still an atomic inline to fit on the line.
2023-12-10 11:09:22 +01:00
Aliaksandr Kalenik
4164af2ca4 LibWeb: Do not compensate padding for abspos boxes with static position
When a box does not have a top, left, bottom, or right, there is no
need to adjust the offset for positioning relative to the padding edge,
because the box remains in the normal flow.
2023-11-15 23:44:05 +01:00
Aliaksandr Kalenik
eac7916d2c LibWeb: Use inner available space to calculate auto height of abspos
By using available_inner_space_or_constraints_from(available_space), we
ensure that the available space used to calculate the min/max content
height is constrained by the width specified for the box itself
(I know that at least GFC always expects available width to be
constrained by specified width if there is any).

This change improves layout in "Recent news" block on
https://telegram.org/
2023-11-15 11:26:14 +01:00
FalseHonesty
2285dfb80e LibWeb: Resolve block max-width percentage against containing block 2023-10-29 19:35:02 +01:00
Aliaksandr Kalenik
c41e742de4 LibWeb: Fix min-content width calculation in dimension_box_on_line()
If inline-block is sized under min-content width constraint we should
use its min-content width instead of max-content width like it was
before.
2023-10-16 21:44:48 +02:00
Sam Atkins
1132c858e9 LibWeb: Stop inserting inline nodes into a generated wrapper box
493dd5d93c caused the `::before`
pseudo-element node to be inserted before the element's content, which
caused issues with how we determine where to insert inline nodes into
the layout tree. At the time, I noticed the issue with contents of flex
containers, and prevented them from merging into a `::before` box.

However, a similar situation happens when we're not in a flex container,
but the pseudo-element has `display: block`. This commit fixes that
situation by using the same logic in both places, so a similar mistake
can't be made again.

This fixes the tab text being invisible on GitHub project pages. :^)
2023-10-11 07:05:23 +02:00
Aliaksandr Kalenik
06d05b3c55 LibWeb: Boxes that establish FFC or GFC should avoid overlapping floats
Before, we only ensured that boxes establishing BFC did not overlap
with floats because that is what CSS 2.2 specification says. However,
we should also apply the same for boxes establishing FFC or GFC as this
aligns with the behavior of other browsers.

Fixes https://github.com/SerenityOS/serenity/issues/21095
2023-09-22 16:48:28 +02:00