When content-visibility:hidden starts skipping a subtree, clear the
stale layout and paint nodes for its descendants.
Preserve SVG mask, clipPath, and pattern resource boxes only when
they are attached to a referencing layout subtree outside the subtree
being hidden. Resources used inside the hidden subtree are cleared
with that subtree, so they rebuild under the live referencing layout
node when the subtree becomes visible again.
Otherwise observed descendants can keep old paintables around after
the current paint tree has been rebuilt without them.
During intrinsic sizing, compute_width() ran on block descendants with
an intrinsic-sizing available space. For a non-FC-establishing block
with auto width, used_width stayed auto, and the min-width clamp then
compared AvailableSize::min-content against min-width via operator<,
which always returns true when the left side is min-content. The clamp
fired with min-width: 0 and set content_width to 0 permanently.
Skip the min-width clamp when used_width is still auto, mirroring the
max-width clamp a few lines above which already no-ops via
to_px_or_zero. The real width is then set by the IntrinsicSizing branch
in layout_block_level_children.
When resolving grid track sizes, limited min/max-content contributions
should be capped by fixed max track sizing functions, including the
argument to fit-content(). We were instead falling back to the grid
container maximum size, which allowed a grid item with overflowing
contents in a fit-content(0) row to inflate the intrinsic block size of
a nested grid.
That bogus intrinsic height could then be used for the grid's second row
sizing pass, causing unrelated flexible rows to absorb the extra space.
Previously, `run_caption_layout()` passed the table's border-box width
as the available space to the caption's formatting context. The BFC then
used this width directly for inline line breaking, causing text to
overflow the caption's content box by the size of the caption's own
border and padding.
Previously, the select button's text was only refreshed inside the
two non-trivial branches of the selectedness setting algorithm.
Paths that left the select with exactly one selected option hit a
no-op branch and skipped the refresh.
Fix this by implementing the "clone selected option into select
button" algorithm and invoking it whenever the set of selected options
may have changed.
Don't rewrite text input 'width: auto' to 'size()ch' in
'HTMLInputElement::adjust_computed_style()'. That turns the control into
a definite-width flex item and prevents 'align-items: stretch' from
expanding it across the flex container.
Fixes the layout of the input element on the element matrix login page.
The replaced element sizing code was comparing tentative used sizes
min-width/min-height and max-width/max-height. For box-sizing:
border-box, that mixes content-box and border-box measurements, which
can clamp replaced-like elements incorrectly.
This could make, for example search/text inputs with explicit height
and padding render too short.
Resolve min/max constraints with calculate_inner_width() and
calculate_inner_height() before clamping so the comparison uses
the same inner sizing space as the tentative replaced size.
Fixes the sizing of the search bar on:
https://tv.apple.com/se
Stop rebuilding the counter style cache from every style update.
That made unrelated restyles pay the full counter-style cost even when
no relevant stylesheet state had changed.
Dirty the cache when stylesheet rule caches are invalidated and rebuild
it on the first counter-style lookup instead. Also make cold cache
rebuilds include user stylesheets.
Add regression tests covering insertRule() and replaceSync() updates
that should make newly defined counter styles take effect.
Fixing float-related intrinsic width bookkeeping exposed that table
captions only contributed their raw min-content width to CAPMIN.
That ignored caption padding, borders, margins, and definite widths,
so captions could be laid out too narrow and wrap content that should
stay beside floats.
Compute each caption's min-content contribution as an outer width and
clamp it against the preferred outer width when the caption has a
definite width. Add a test for a fixed-width caption with a float and
rebaseline the existing padded-caption layout test.
BlockFormattingContext::greatest_child_width() tried to decide whether
a line overlapped a float by comparing a line-relative baseline
against float edges stored in containing-block coordinates. That also
used `||`, so later lines could keep inheriting float width even after
the float had ended.
Measure overlap using each line box's top and bottom edges in the same
coordinate space as the float margins instead. This fixes
shrink-to-fit and max-content sizing for inline children after short
floats.
Add left and right tests where a later forced-break line is longer
than the line next to the float.
Add a right-side mirror of the existing overflow:hidden test with a
nested block and margin-right on the containing block.
This exercises the float-avoidance bookkeeping for a BFC that has to
sit beside a right float in nested coordinates.
CSS2 requires moving a float downward until it fits beside existing
floats. We already handled same-side blockers, but opposite-side
blockers could still overlap, such as matching left and right 100%
floats.
Recompute same-side bookkeeping after lowering and measure
opposite-side intrusion in the current containing block's coordinate
space. Also account for the full inline space already occupied on the
current side after same-side stacking, so a float shifted next to an
earlier same-side float does not still overlap an opposite-side float.
Add tests covering inline and nested lowering, stale same-side line
state, staggered opposite-side stacks, and the left/right/left 600px
overlap case. Update the stacked clear-both expectation to match the
corrected placement.
When multiple floats are stacked vertically (e.g. multiple width:100%
left floats), the float placement code clears current_boxes as each
new "float line" begins. This meant that clear_floating_boxes() only
saw the last stacked float, not all preceding ones.
Fix this by iterating all_boxes instead of current_boxes when computing
clearance. Also move set_content_y() before the FloatingBox creation so
the root-space rect stored in all_boxes has the correct Y position.
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()
These tests demonstrate incorrect behavior where percentage heights
and max-heights resolve against the viewport instead of being treated
as auto/none inside auto-height tables.
Let labels fall back to their default inline display so empty
labels do not create extra line height above following
block content.
Add a regression for the empty-label case and update the
file input layout expectation for the UA shadow label.
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
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.
Input elements with a placeholder were positioned lower than inputs
without a placeholder or inputs with text. This was caused by the
placeholder element missing height height and overflow properties that
the inner text element had.
This fix makes sure both the placeholder and inner text elements let
show the same position of the input field.
The spec says that the `system` descriptor defaults to `symbolic` but
previously we just ignored any `@counter-style` rules without a `system`
descriptor
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.
The `is_ignorable_whitespace()` check in table fixup traverses anonymous
block wrappers to see if they contain only whitespace. It rejected
out-of-flow and text descendants but silently skipped in-flow non-text
elements like `<span>`, misclassifying wrappers with real content as
ignorable and absorbing them into the table structure.
Absolutely positioned elements inside SVG foreignObject were being
positioned relative to an ancestor containing block outside the SVG,
instead of relative to the foreignObject itself. Per a W3C resolution
and the behavior of other browsers, foreignObject should establish a
containing block for absolutely and fixed positioned elements.
With this fix, the `has_abspos_with_external_containing_block` check
in `set_needs_layout_update()` and the abspos preservation loop in
`relayout_svg_root()` become dead code — remove both and simplify the
ancestor loops. Rename related tests to reflect the new behavior.
Fixes https://github.com/LadybirdBrowser/ladybird/issues/3241
Before this change we would only account for the size of the list item
itself rather than it's marker which if the marker was larger than it's
associated list item could lead to markers overlapping
The CSS spec (CSS2 10.6.4 / CSS Position 5.3) says:
1. Compute tentative height without min/max-height
2. If result > max-height, re-solve with max-height as height
3. If result < min-height, re-solve with min-height as height
We already implemented this correctly for the width axis, but the
height axis tried to bake min/max constraints into the solve_for
lambda. This corrupted the constraint equation when solving for
height with auto height + min-height, since the height term couldn't
cancel itself out (it was inflated to min-height on subtraction but
stayed 0 on addition).
This caused abspos elements with top+bottom insets and min-height to
incorrectly get the min-height as their height, even when the
containing block was tall enough for a larger height.
Previously, horizontal padding, border, and margin were not being
resolved for table captions. This was visible in layout tests where
captions with padding showed 0 in the width metrics.
`grid-template-rows: fit-content(100px)` had no effect when the grid
container lacked an explicit height, because the fit-content growth
limit clamping was gated behind `available_size.is_definite()`.
Fix by normalizing fit-content tracks with unresolvable percentage
arguments to max-content during track initialization, then applying
the fit-content clamp unconditionally.
Fixes https://github.com/LadybirdBrowser/ladybird/issues/7730
While our default font supporting variations is unlikely, this is
nevertheless required for our fallback font to be considered equal to
it's non-default/fallback equivalent (i.e. `font-family: serif`) which
in turn is required for LineBuilder to merge chunks into a single
fragment.
In quirks mode, the body element expands to fill its parent (the html
element) when height is auto, per the quirks spec section 3.7.
This quirk applies when:
- The document is in quirks mode
- The body element has height: auto
- The body is not absolutely/fixed positioned
- The body is not floated
- The body is not inline-level
Add tests to verify:
- Buttons have reasonable height in quirks mode (not collapsed)
- Flex containers with percentage height use quirks walk-up to viewport
- Flex items with percentage height do NOT use quirks walk-up
For `float: left` boxes, we would take the available space into account
and push boxes down as required. This applies that same logic to `float:
right` boxes, where we would previously only compare their offset from
the edge using `>= 0`, which was almost always true.
Fixes#4750.
Previously, buttons with `display: block` and `width: auto` would take
an early return path in compute_width() that set the content width to
fit-content but skipped all margin resolution. This meant `margin: auto`
would not center the button horizontally.