Commit Graph

895 Commits

Author SHA1 Message Date
Jelle Raaijmakers
3d2571b46e LibWeb: Implement text-decoration-skip-ink painting
Use Skia's SkTextBlob::getIntercepts() to find where glyph outlines
cross the underline/overline band, then split the decoration line into
segments with gaps around those intersections.
2026-03-26 12:15:36 +00:00
Callum Law
b86377b9dc LibWeb: Clamp CSS <integer> value to i32 at parse time
This matches the behavior of other browsers. Previously we implemented
this at used-value time for z-index specifically.
2026-03-26 12:30:01 +01:00
Jelle Raaijmakers
c07e92fc7e LibWeb: Apply text-overflow ellipsis as line box post-processing
The previous implementation checked text-overflow and overflow-x
on the text node's direct parent during inline item iteration.
Since these are non-inherited properties, ellipsis only worked
for text directly inside the block container, not when wrapped
in inline elements like <span> or <a>.

Move ellipsis truncation to a post-processing step after line
boxes are constructed, checking the containing block instead.
2026-03-26 00:19:50 +00:00
Tim Ledbetter
d69d74e7ce LibWeb: Always shift line boxes below floats when content does not fit
Previously, this wasn't done when placing the first inline content in a
block, which caused long unbreakable words to overlap with floats
instead of being moved below them.
2026-03-25 21:28:57 +01:00
Luke Wilde
df32da5e86 LibWeb: Make every HTMLElement potentially form-associated
This can be the case for form-associated custom elements, where any
HTML element can be form-associated.
2026-03-25 13:18:15 +00:00
Callum Law
f347be8206 LibWeb: Store underlying RatioStyleValue values as StyleValues
Previously we stored a fully formed `Ratio` - this restricted us from
supporting calculated values which will be implemented in a later commit
2026-03-24 14:00:01 +00:00
Callum Law
b07ef9435e LibWeb: Remove fallback behavior from color_or_fallback
All of the properties using this method only accept color values so the
fallback behavior wasn't required
2026-03-24 13:56:01 +01:00
Callum Law
e2f2f813b6 LibWeb: Handle accent-color auto value explicitly
`accent-color` is the only user of the fallback functionality of
`color_or_fallback`, by handling this explicitly we can remove that
fallback functionality in a later commit.

Also includes a couple of improvements for `accent-color` specifically:
 - We don't set it in `ComputedValues` twice.
 - `ComputedProperties::accent_color` returns a non-optional value
   (since we always have one)
 - `ComputedProperties::accent_color` takes a `ColorResolutionContext`
   instead of generating one itself from a `LayoutNode`, this will allow
   us to reuse shared resolution contexts in the future
2026-03-24 13:56:01 +01:00
Jelle Raaijmakers
277512ce01 LibWeb: Implement CSS flexbox baseline aligned items 2026-03-24 05:13:49 +01:00
Andreas Kling
8836f28267 LibWeb: Don't walk past anonymous table cells for percentage resolution
When resolving percentage heights/widths against the containing block,
we walk past anonymous boxes to find the relevant ancestor. However,
anonymous table cells are proper containing blocks with their own
sizing semantics. Walking past them caused us to reach the viewport
and incorrectly resolve percentages against the viewport size.

Fix this in all affected places in FormattingContext:
- should_treat_height_as_auto()
- calculate_inner_height()
- should_treat_max_height_as_none()
- should_treat_max_width_as_none()
- compute_inset() percentage-as-auto check
- solve_replaced_size_constraint()
- compute_height_for_replaced_element()
2026-03-23 16:40:38 +01:00
Psychpsyo
98e1774eff LibWeb: Avoid division by zero in multicol calculations the right way
This got changed a while back to avoid a divide-by-0. That change was
not following the spec at all and would've resulted in incorrect values
being used, so this is the spec-compliant way of resolving that.

I originally didn't add spec comments to this algorithm since it felt
weird, but I hope these will demonstrate that this should not be changed
on a whim until we can import the relevant WPT tests for this behavior.
2026-03-23 12:09:29 +01:00
Psychpsyo
ce36e1f7df LibWeb: Do not allow margins collapsing through IFCs
Co-authored-by: ChaseKnowlden <haroldknowlden@gmail.com>
2026-03-23 11:34:33 +01:00
Andreas Kling
c5d7898b41 LibWeb: Resolve grid item height via aspect-ratio for non-stretch items
When a grid item has a preferred aspect-ratio, a definite width, and
non-stretch alignment, resolve its height through the aspect-ratio
instead of using fit-content sizing.

The fit-content height calculation was incorrectly using the available
width (grid area width) to compute the aspect-ratio-based height,
rather than using the item's actual resolved width. This caused items
like a 50px wide div with aspect-ratio: 1/1 to get a height of 784px
(the grid area width) instead of 50px.
2026-03-21 23:16:32 -05:00
Andreas Kling
cf3d9c1bae LibWeb: Fix static position of inline-level abspos elements in BFC
When an absolutely positioned element's display was inline-level
before blockification, and its preceding sibling is an anonymous
wrapper with inline children, the element's static position should
be at the same vertical position as that wrapper. This matches where
the element would have been placed if it were still inline.

Previously, the static position was always set to the current block
offset (after the preceding block), which placed the element below
the inline content instead of beside it. This caused absolutely
positioned ::after pseudo-elements (like dropdown chevrons) to appear
on the line below the text instead of at the same vertical position.
2026-03-21 21:42:44 -05:00
Andreas Kling
3b1bbd7360 LibWeb: Respect box-sizing when computing grid item minimum contribution
When computing the minimum contribution of a grid item with a definite
minimum size (e.g. min-height: 3rem), we must convert the CSS value to
content-box size before adding margin-box sizes. With box-sizing:
border-box, the CSS value already includes padding and border, so
passing it directly to add_margin_box_sizes() double-counted them.

Use calculate_inner_width/calculate_inner_height to properly convert
the minimum size to content-box dimensions, consistent with how
preferred and maximum sizes are already handled in the grid track
sizing algorithm.
2026-03-21 21:42:44 -05:00
Andreas Kling
b07a19e35f LibWeb: Account for letter-spacing when trimming trailing whitespace
When trimming trailing whitespace from line boxes, we were only
subtracting the glyph width of each trimmed character. However, during
text shaping, letter-spacing is added to each glyph's advance width.
We must subtract the full advance (glyph width + letter-spacing) to
get an accurate line width after trimming.

This also fixes a pre-existing precision bug where the glyph width
(a float) was truncated to int, leaving fractional phantom width in
the line box.

Together, these issues caused text with letter-spacing and trailing
HTML whitespace to have an underestimated intrinsic width, leading to
unexpected text wrapping in flex layouts.
2026-03-21 21:42:44 -05:00
Andreas Kling
b102a68746 LibWeb: Precompute contained boxes map for measure_scrollable_overflow
Build a HashMap from each containing block to the boxes it contains
before measuring scrollable overflow. This allows
measure_scrollable_overflow() to iterate only the relevant boxes
directly, rather than walking the entire layout subtree and filtering
by containing_block() at each node.
2026-03-21 18:20:09 -05:00
Tim Ledbetter
cd9a76902b LibWeb: Avoid applying viewbox transform multiple times for nested SVGs
The parent's viewBox transform includes both scaling and a centering
offset. For nested <svg> elements, this transform was applied once to
position the nested SVG's box, then again to position children inside
it, double-counting the centering offset.

We now apply the parent's transform to the nested SVG box upfront to
ensure the transform is only applied once.
2026-03-20 15:59:44 -05:00
Tim Ledbetter
60334b3464 LibWeb: Treat percentage insets as auto for indefinite containing blocks 2026-03-20 15:58:50 -05:00
Zaggy1024
44ed698d4f LibWeb: Separate the active element and the element being activated
We were conflating elements being the active element and elements being
activated. The :active pseudo class is supposed to be based on whether
an element will have its activation behavior run upon a button being
released.

Store whether an element is being activated as a flag that is set/reset
by EventHandler.

Doing this allows label elements to visually activate their control
without doing a weird paintable hack, so the Labelable classes have
been yeeted.
2026-03-17 04:01:29 -05:00
dominick038
76c65eca57 LibWeb: Clamp saturated CSSPixels values before make_definite() 2026-03-11 17:23:35 +01:00
Tim Ledbetter
2b8967d55f LibWeb: Distribute grid track free space among unfrozen tracks only
Previously, during grid track maximization we used the total number of
grid tracks as the denominator when distributing the available free
space. Using a larger denominator than expected meant that the
algorithm needed a larger number of iterations than necessary to
converge leading to rounding errors in the final track sizes.
2026-03-10 22:39:55 +01:00
Jelle Raaijmakers
09be72f9e6 LibWeb: Calculate a <fieldset>'s client height correctly
We were not properly including the impact of the fieldset's legend in
the client height, which caused us to report values that were different
than those from other browsers.
2026-03-10 19:08:15 +00:00
Jelle Raaijmakers
f61528238e LibWeb: Replace is<T> + as<T> with as_if<T>
Doing so results in a single fast_if<T> or dynamic_cast<T> call instead
of two. No functional changes.
2026-03-10 15:17:51 +01:00
Tim Ledbetter
483ea12914 LibWeb: Reinitialize TextNode chunk state after collapsing whitespace
When collapsible whitespace is skipped without committing a prior
chunk, the loop would fall through and continue with font information
derived from the last whitespace code point rather than the next
non-whitespace character. Restart the function via recursion so that
these values are reinitialized from the correct code point.
2026-03-09 15:34:34 +01:00
Psychpsyo
f7e1c8cf6b LibWeb: Add spec comment to algorithm 2026-03-07 17:17:18 +01:00
Tim Ledbetter
2fbc4d26ff LibWeb: Allow SVG root elements to participate in inline continuation 2026-03-05 17:16:42 +01:00
Jelle Raaijmakers
344b1a1ddc LibWeb: Hoist fieldset contents into anonymous wrapper
Make an anonymous wrapper for a fieldset's contents, excluding its
legend, as the spec asks us to do. This will make sure we can apply
certain CSS properties to the correct box.

Fixes #6747
2026-03-04 20:39:01 +01:00
Jelle Raaijmakers
8aef896b11 LibWeb: Rework <fieldset> and <legend> rendering
We were misaligning <fieldset>'s bounds, painting and <legend> layout in
many cases. This reworks both the layout and painting code to the point
where we render many cases practically identical to Firefox and Chrome.
2026-03-04 20:39:01 +01:00
Aliaksandr Kalenik
490377b76e LibWeb: Populate containing block chain in BFC min-height measurement
The throwaway BFC for min-height measurement may encounter abspos
elements whose CSS containing block is an ancestor above the subtree
root. Populate the entire containing block chain (not just the immediate
parent) so that ensure_used_values_for() finds pre-existing entries
instead of hitting the subtree root VERIFY.

Stop walking when the source state lacks an entry, which handles the
nested throwaway state case (e.g. min-height inside intrinsic sizing).
2026-03-03 22:37:38 +00:00
Aliaksandr Kalenik
8527da249e LibWeb: Use parent layout mode for BFC min-height measurement
The throwaway min-height measurement in layout_block_level_box was
using LayoutMode::IntrinsicSizing, which caused flex/grid formatting
contexts to hit their early-exit optimization and return zero content
height. This incorrectly forced min-height as the available height.

Fixes https://github.com/LadybirdBrowser/ladybird/issues/8249
2026-03-03 22:37:38 +00:00
Michael Watt
1243dbd72f LibWeb: Create absolute container for will-change: position
This fixes:
http://wpt.live/css/css-will-change/will-change-abspos-cb-001.html
2026-03-03 16:52:57 +01:00
mikiubo
bee9d1e19e LibWeb: Add synthetic height for contenteditable elements
Contenteditable elements that would otherwise have zero height now get a
minimum height equal to their line-height.
This ensures they remain clickable and usable for text editing.

This fixes the WPT test:
contenteditable/synthetic-height.html
2026-03-03 16:20:10 +01:00
Aliaksandr Kalenik
edf1ca8f19 LibWeb: Restrict throwaway layout states to their subtree
Throwaway LayoutState instances used for intrinsic sizing should not
access nodes outside the laid-out subtree. Make this explicit by setting
a subtree root on each throwaway state, pre-populating only the
immediate containing block, and using try_get() for any ancestor
lookups — treating unavailable ancestors as indefinite rather than
silently populating them with incorrectly-resolved values.
2026-02-27 19:11:41 +01:00
Callum Law
858989e006 LibWeb: Make CounterStyle ref counted
Previously we just passed around a reference to the `CounterStyle`
stored on `Document::registered_counter_styles` but this won't be
possible for anonymous counter styles (i.e. those created by the
`<symbols()>` function)
2026-02-27 16:25:53 +00:00
Tim Ledbetter
a762f623bd LibWeb: Implement SVGPatternElement 2026-02-27 17:14:50 +01:00
Tim Ledbetter
000a746b78 LibWeb: Apply SVG transforms to image elements during layout 2026-02-27 17:14:50 +01:00
Tim Ledbetter
804287847a LibWeb: Add SVG paint fallback color support to CSS parsing 2026-02-27 17:14:50 +01:00
Aliaksandr Kalenik
a7993e240b LibWeb: Skip BFC abspos static position in intrinsic sizing
Avoid calculating static positions for absolutely positioned boxes
during intrinsic sizing, where the positions are based on intermediate
state and will be recalculated during normal layout. This is consistent
with how all other formatting contexts (IFC, TFC, GFC, FFC) handle
abspos boxes during intrinsic sizing.
2026-02-27 15:03:59 +01:00
Aliaksandr Kalenik
0c2212813c LibWeb: Use IntrinsicSizing mode for min-height measurement in BFC
When measuring content height to compare against min-height, a
throwaway formatting context was created with m_layout_mode (the
parent's layout mode, which could be Normal). This is a measurement
operation and should use LayoutMode::IntrinsicSizing instead,
consistent with the similar measurement in FormattingContext.cpp.
2026-02-27 12:48:27 +01:00
Psychpsyo
f7f95d2611 LibWeb: Do not remove inline start padding when collapsing whitespace 2026-02-27 12:05:03 +01:00
Aliaksandr Kalenik
d163c11612 LibWeb: Skip IFC abspos static position in intrinsic sizing
BFC, TFC, GFC, and FFC all skip absolutely positioned element handling
during intrinsic sizing. IFC was the only formatting context that
unconditionally calculated static positions for abspos elements.

This is unnecessary during intrinsic sizing because the positions are
based on intermediate state and will be recalculated during normal
layout. It also avoids creating UsedValues entries for abspos boxes
that serve no purpose during intrinsic sizing.
2026-02-27 11:43:53 +01:00
Andreas Kling
a146225331 LibWeb: Use unsafe layout/paintable accessors where appropriate
Add unsafe_layout_node(), unsafe_paintable(), and unsafe_paintable_box()
accessors that skip layout-staleness verification. These are for use in
contexts where accessing layout/paintable data is legitimate despite
layout not being up to date: tree construction, style recalculation,
painting, animation interpolation, DOM mutation, and invalidation
propagation.

Also add wrapper APIs on Node to centralize common patterns:
- set_needs_display() wraps if (unsafe_paintable()) ...set_needs_display
- set_needs_paint_only_properties_update() wraps similar
- set_needs_layout_update() wraps if (unsafe_layout_node()) ...

And add Document::layout_is_up_to_date() which checks whether layout
tree update flags are all clear.
2026-02-26 21:09:08 +01:00
Andreas Kling
ed26fdaa81 LibWeb: Remove ViewportClient from ImagePaintable and VideoBox
Neither of these classes did anything useful as ViewportClients:

- ImagePaintable called set_visible_in_viewport() which is a FIXME
  no-op in every ImageProvider implementation.
- VideoBox had an empty did_set_viewport_rect() with a FIXME comment.

More importantly, they caused a crash when a DOM node was adopted into
a different document: the old ImagePaintable/VideoBox would still be
registered with the old document, but their document() accessor (which
goes through the DOM node) would return the new document. During GC
finalization, unregister_viewport_client() would fail because it was
trying to unregister from the wrong document.

The only meaningful ViewportClient is HTMLImageElement (for responsive
image source selection), which already handles document adoption
correctly in adopted_from().

Fixes crash when loading https://msn.com/
2026-02-26 09:25:25 +01:00
Tim Ledbetter
f05bc7c0cd LibWeb: Implement dominant-baseline for SVG text
This property determines the default baseline used to align content
within the given box.
2026-02-26 09:23:23 +01:00
Tim Ledbetter
245eb7d91d LibWeb: Use margin box for vertical overlap checks in float placement
Previously, a float with `padding-top` would overlap a preceding float
instead of being placed beside it. The vertical overlap check was
comparing the new float's content box Y,which includes the padding
offset, against preceding floats' margin box rects, causing the check
to incorrectly conclude the floats do not overlap.
2026-02-25 12:03:31 +01:00
Tim Ledbetter
6b3d3468a1 LibWeb: Account for <col> span attribute during table grid formation
Previously, the column count was always incremented by 1. This led to a
mismatch with `compute_outer_content_sizes()`, which did use the `span`
attribute to advance the column index. This mismatch caused an
out-of-bounds access when the column index was greater than the
expected number of columns.
2026-02-24 12:14:54 +01:00
Callum Law
8d4084261a LibWeb: Resolve list item marker using registered counter styles 2026-02-23 11:21:09 +00:00
Callum Law
32b9ff21df LibWeb: Add generic int_from_style_value method
Reduces duplication in line with `number_from_style_value`,
`string_from_style_value` etc
2026-02-23 11:21:09 +00:00
Zaggy1024
21019c2fa9 LibWeb: Use UA shadow DOM for media elements' controls
Instead of using a custom paintable to draw the controls for video and
audio elements, we build them out of plain old HTML elements within a
shadow root.

This required a few hacks in the previous commits in order to allow a
replaced element to host children within a shadow root, but it's
fairly self-contained.

A big benefit is that we can drive all the UI updates off of plain old
DOM events (except the play button overlay on videos, which uses the
video element representation), so we can test our media and input event
handling more thoroughly. :^)

The control bar visibility is now more similar to how other browsers
handle it. It will show upon hovering over the element, but if the
cursor is kept still for more than a second, it will hide again. While
dragging, the controls remain visible, and will then hide after the
mouse button is released.

The icons have been redesigned from scratch, and the mute icon now
visualizes the volume level along with indicating the mute state.
2026-02-23 07:27:31 +01:00