Commit Graph

87 Commits

Author SHA1 Message Date
Aliaksandr Kalenik
e87fece8c6 LibWeb: Force position:static on non-root SVG elements
SVG elements (except the outermost <svg>) use SVG's coordinate system,
not the CSS box model, so CSS positioning doesn't apply to them.

This adds SVGElement::adjust_computed_style() to force position:static
on all SVG elements except the outermost <svg> element (which has no
owner_svg_element()). SVGSymbolElement's existing override now calls
Base::adjust_computed_style() to inherit this behavior.

With this in place, the FIXME in layout_absolutely_positioned_element()
for SVG boxes becomes unreachable and is replaced with
VERIFY_NOT_REACHED().
2026-02-21 05:12:55 +01:00
Jelle Raaijmakers
6a29b8cc03 LibWeb: Derive inline-block baseline from nested content
Compute inline-block baselines by traversing into nested block children
to find the last in-flow line box, using correct offsets relative to the
margin box edge.

Also ensure inline-flex and inline-grid containers always derive their
baseline from content (per CSS Align), and add special handling for
<input> elements which have `overflow: clip` in the UA stylesheet but
should still align adjacent text with their internal content.
2026-01-22 19:36:09 +01:00
Aliaksandr Kalenik
defbd0ec05 LibWeb/SVG: Percent-decode same-document <use> href fragments
`SVGUseElement::referenced_element()` previously passed
`m_href->fragment()` directly to `Document::get_element_by_id()`. URL
fragments are stored in their serialized form, so references to elements
whose IDs contain non-ASCII characters would fail to resolve.
2025-12-23 00:11:42 +01:00
Psychpsyo
5c67ea640a LibWeb: Propagate overflow to viewport more correctly 2025-12-15 09:47:25 +00:00
Jelle Raaijmakers
39ad7833f0 LibWeb: Do not render SVG <symbol> elements unless part of <use>
We were always rendering <symbol> SVG elements, but we should only
render them if they are a child of a <use>'s shadow root. This caused
practically all instances of <symbol> to be drawn at least one time too
many.
2025-11-27 07:55:29 +01:00
Jelle Raaijmakers
2c5beeabe3 LibWeb: Improve support for SVG text positioning attributes
Previously, we only supported very basic numbers and a single level of
text positioning support in the `x`, `y`, `dx` and `dy` attributes in
`<text>` and `<tspan>` SVG elements.

This improves our support for them in the following ways:

  * Any `length-percentage` or `number` type value is accepted;
  * Nested `<text>` and `<tspan>` use the 'current text position'
    concept to determine where the next text run should go;
  * We expose the attributes' values through the API.

Though we still do not support:

  * Applying the `rotate` attribute;
  * Applying transformations on a per-character basis.
  * Proper horizontal and vertical glyph advancing (we just use the path
    bounding box for now).
2025-11-20 23:15:24 +01:00
Andreas Kling
d36e5098f8 LibWeb: Support percentage attributes on SVG rect element
This makes the IMDb logo have a yellow background as expected.
2025-09-28 19:25:18 +02:00
Jelle Raaijmakers
f4b04beccd LibWeb: Show inline positioning in layout tree dump
Inline nodes in our layout tree have a position, so let's show it. By
centralizing the logic for this, block nodes now lose their redundant
'content-size' dump info which is already part of the box model dump.
2025-08-27 11:53:45 +01:00
Jelle Raaijmakers
e173b00db6 LibWeb: Always show box model info when dumping layout tree
This is useful information. Let's not hide it.
2025-08-27 11:53:45 +01:00
Andreas Kling
8e49b69f42 LibWeb: Never split <svg> for inline continuations
This fixes an issue where we'd make an absolute mess from nested SVG
roots with display:block. Before this fix, the inner SVG root would
trigger the inline continuation logic and try to split the tree.
2025-07-12 14:11:41 +02:00
Andreas Kling
4e23882995 LibWeb: Use foreignObject's own size as available space inside it
This ensures that percentages resolve against the foreignObject's size
instead of the size of its containing block.

This makes user profile pictures clip correctly in the "Friends" view
of the Discord app.
2025-07-12 14:11:41 +02:00
Jelle Raaijmakers
2998049fe9 LibWeb: Implement the unreachable scrollable overflow
Whenever we end up with a scrollable overflow rect that goes beyond
either of its axes (i.e. the rect has a negative X or Y position
relative to its parent's absolute padding box position), we need to clip
that rect to prevent going into the "unreachable scrollable overflow".

This fixes the horizontal scrolling on https://ladybird.org (gets more
pronounced if you make the window very narrow).
2025-07-11 08:23:46 +02:00
Andreas Kling
aae0b52403 LibWeb: Resolve mask/clip in foreignObject's own coordinate space
We were neglecting to resolve these correctly, which caused them to get
the same metrics as the nearest viewport above the foreignObject.
2025-07-09 14:36:08 +02:00
Andreas Kling
f5f3cd041a LibWeb: Apply SVG viewbox transform to foreignObject elements 2025-07-09 14:36:08 +02:00
Andreas Kling
f343a418b2 LibWeb: Never split SVG foreignObject for inline continuations
This would produce a bizarre layout tree and certainly not yield
expected results.
2025-07-09 14:36:08 +02:00
Andreas Kling
b4708510fb LibWeb: Layout foreignObject as block-level element with hidden overflow
This is according to the default user-agent style from the SVG2 spec.

In order for this to work correctly, we also have to assign width and
height to foreignObject boxes during SVG layout, since they are handled
manually by SVGFormattingContext.
2025-07-09 14:36:08 +02:00
Andreas Kling
ddcb87fb40 LibWeb: Make TreeBuilder nicer to SVG foreignObject
This patch does two things:

1. Makes TreeBuilder never cross the foreignObject boundary when looking
   for an appropriate insertion parent. Before this change, we would
   sometimes make things inside the foreignObject DOM subtree have
   layout nodes outside the foreignObject.

2. Makes foreignObject boxes participate in the anonymous wrapping of
   inline-level boxes. This is particularly imporant for absolutely
   positioned elements inside foreignObject, which were previously
   getting incorrectly wrapped if there was any text (even empty)
   preceding the abspos element.
2025-07-09 14:36:08 +02:00
Andreas Kling
07838016c8 LibWeb: Make layout code aware that we create BFC for foreignObject
We were already always doing this, but through an unusual mechanism:
SVG layout creates a BFC on the stack when laying out foreignObject
subtrees.

This change makes the rest of the layout system aware of this, and
also allows it to be reflected in layout dumps.
2025-07-09 14:36:08 +02:00
Andreas Kling
0cf9a4543a LibWeb: Make SVG foreignObject establish a new stacking context
This matches the behavior of Blink and Gecko, but not WebKit.
2025-07-09 14:36:08 +02:00
Andreas Kling
dab1fd265d test-web: Dump stacking context tree in layout test output
This will allow us to test (and catch regressions in) stacking context
tree construction and updates, etc.
2025-07-09 14:36:08 +02:00
Aliaksandr Kalenik
9e232a70c3 LibWeb: Allow descendant boxes to contribute in overflow rect of parent
...with inline children. This fixes an issue when we ignore abspos boxes
contained by PaintableWithLines while calculating overflow rect size.

Lots of layout tests are affected, because now PaintableWithLines has
overflow rect.

`Text/input/DOM/Element-set-scroll-left.html` is also affected and now
matches other browsers.
2025-07-06 17:10:18 +02:00
Tim Ledbetter
05ef650a59 LibWeb: Respect presentation attributes that apply to not all elements
Some SVG presentation attributes are only supported on certain
elements. We now support these special cases for attributes and
elements that we currently have implemented.
2025-07-05 19:07:06 -04:00
Jelle Raaijmakers
c03210e858 LibWeb: Dump PaintableBox dimensions for inline layout nodes
We were only dumping a PaintableBox' dimensions if its layout node was a
Layout::Box as well, causing us to not dump the dimensions of paintables
for inline nodes in the paintable tree.
2025-07-03 22:16:48 +02:00
Jelle Raaijmakers
71665fa504 LibWeb: Scale font size by 1.15 for line-height: normal
Browsers such as Chrome and Firefox apply an arbitrary scale to the
current font size if `normal` is used for `line-height`. Firefox uses
1.2 while Chrome uses 1.15. Let's go with the latter for now, it's
relatively easy to change if we ever want to go back on that decision.

This also requires updating the expectations for a lot of layout tests.
The upside of this is that it's a bit easier to compare our layout
results to other browsers', especially Chrome.
2025-05-05 13:15:56 +02:00
Psychpsyo
d048ee3155 Meta: Add doctypes to all svg layout tests 2025-05-04 11:23:52 +02:00
Jelle Raaijmakers
c0109039cb LibWeb: Do not consider <foreignObject> for inline continuation
We used to have an exception for this element that erroneously got
removed in 336684bc5c.

Fixes #3453.
2025-02-19 13:49:24 +01:00
Shannon Booth
b7512deada LibWeb/SVG: Fix crash when SVG use element is used on an external SVG
We were previously crashing when invoking 'scroll to the fragment' on
such documents as it was unable to find the active document. This is
as a result of our AD-HOC implementation not setting up the document
fully to mark it is active before running the parser.

Fixes a crash on https://tweakers.net.
2025-01-19 15:01:39 +01:00
Manuel Zahariev
5d85f3a5c8 LibWeb: Test layout of standalone SVG document: edge cases
Tests with different combinations of missing width, height
and viewBox.

All tests confirmed to work on Ladybird:
 - exactly the same as Chromium (131.0.6778.85)
 - almost the same as Firefox (129.0.2)
    - only difference: standalone-w.svg: same size, different alignment
2024-12-13 15:02:49 +00:00
Manuel Zahariev
5d77104c2f LibWeb: Test layout of standalone SVG document: main use case
SVG document with specified width and height attributes is layed out
with this width/height.
2024-12-13 15:02:49 +00:00
Jelle Raaijmakers
352a66390f LibWeb: Do not resolve inline block height early if height is definite
This condition was included to implement flex containers with auto
height, but it actually can reset the definitive height to 0 for inline
blocks with only replaced elements such as an SVG. Removing the
condition does not break any in-tree test, so let's improve the
situation on the SVG side of things for now.
2024-10-25 15:13:30 +02:00
Aliaksandr Kalenik
6a549f6270 LibWeb: Replace InlinePaintable with PaintableWithLines created per line
InlinePaintable was an ad-hoc paintable type required to support the
fragmentation of inline nodes across multiple lines. It existed because
there was no way to associate multiple paintables with a single layout
node. This resulted in a lot of duplicated code between PaintableBox and
InlinePaintable. For example, most of the CSS properties like
background, border, shadows, etc. and hit-testing are almost identical
for both of them. However, the code had to be duplicated to account for
the fact that InlinePaintable creates a box for each line. And we had
quite many places that operate on paintables with a code like:
```
if (box.is_paintable_box()) {
  // do something
} else (box.is_inline_paintable()) {
  // do exactly the same as for paintable box but using InlinePaintable
}
```

This change replaces the usage of `InlinePaintable` with
`PaintableWithLines` created for each line, which is now possible
because we support having multiple paintables per layout node. By doing
that, we remove lots of duplicated code and bring our implementation
closer to the spec.
2024-10-16 20:25:42 +02:00
Andreas Kling
f1be662f68 LibWeb: Always blockify the root element
This is what the spec tells us to do:

    The root element’s display type is always blockified,
    and its principal box always establishes an independent
    formatting context.

    Additionally, a display of contents computes to block
    on the root element.

Spec link: https://drafts.csswg.org/css-display/#root

Fixes #1562
2024-09-29 11:46:13 +02:00
Aliaksandr Kalenik
fa907029ee LibWeb: Print FIXME instead of crashing in abspos SVG element layout
Currently we are crashing in `verify_cast<BlockContainer>(box)` on
attempt to create BFC for SVG box.
2024-09-18 15:50:05 +02:00
Andreas Kling
8eacfc8f10 LibWeb: Derive SVG root's natural size from width/height attributes
We were incorrectly looking at the CSS computed values for width and
height to determine the natural size of <svg> root elements.
This meant that elements where the attribute and computed value were
different values would end up with incorrect natural size.
2024-08-22 15:29:29 +02:00
Aliaksandr Kalenik
c87214d79c LibWeb: Skip documents of decoded SVGs while processing HTML event loop
None of HTML event loop processing steps are relevant for decoded SVGs,
so we can simply skip them while collecting documents for processing.
2024-08-19 09:03:33 +02:00
Tim Ledbetter
4cdafea363 LibWeb: Don't crash when SVG viewbox has a width of 0
Previously, `SVGSVGBox` would have a natural aspect ratio of 0 if it
had a viewbox with zero width. This led to a division by zero, causing
a crash.

Found by Domato.
2024-07-22 09:13:25 +02:00
Edwin Hoksberg
ac6126e263 LibWeb: Support percentage values in SVG line element 2024-07-21 19:56:38 +02:00
MacDue
d7b77d7695 LibWeb: Split SVGFormattingContext up into functions
Doing multiple `for_each_in_subtree()` passes was kind of a hack. We
can resolve everything in a single pass with a little more control over
the layout process. This also fixes a few minor issues like the sizing
of nested `<g>` elements.

More work is needed here though as this is still fairly ad-hoc.

Note: This does regress `css-namespace-tag-name-selector.html`,
previously SVG text within `<a>` elements would appear. However, this
was only because `for_each_in_subtree()` would blindly look through the
InlineNodes from the unimplemented `SVGAElement`s.
2024-04-08 14:24:35 +02:00
Andreas Kling
dd3e002ecf LibWeb: Make empty images (no bitmap, no alt text) take no layout space
This matches the behavior of other browsers.
2024-03-29 08:52:55 -04:00
MacDue
163b6bb401 LibWeb: Special case SVG masks during layout
Rather than try to lay out masks normally, this updates the TreeBuilder
to create layout nodes for masks as a child of their user (i.e. the
masked element). This allows each use of a mask to be laid out
differently, which makes supporting `maskContentUnits=objectBoundingBox`
fairly easy.

The `SVGFormattingContext` is then updated to lay out masks last (as
their sizing may depend on their parent), and treats them like
viewports.

This is pretty ad-hoc, but the SVG specification does not give any
guidance on how to actually implement this.
2024-03-12 08:51:50 +01:00
MacDue
15e3b0ebde LibWeb: Use SVGGraphicsBox for <symbol> and <use> elements
This allows various SVG properties (like masking) to be applied to these
elements.
2024-03-12 08:51:50 +01:00
MacDue
74b655d035 LibWeb: Update SVG <circle> element to use geometry properties
With this the `<circle>` element now correctly parses percentage sizes,
and resolves them relative to the viewport.

The rest of the geometry elements are still left TODO.
2024-03-04 10:50:32 +01:00
Timothy Flynn
abaca60f9a Tests/LibWeb: Move LibWeb test SVGs to their own directory 2024-02-19 22:11:59 -05:00
MacDue
2ede299b4a headless-browser: Run .svg dump tests
Previously, the check for `.html` meant that `.svg` tests were excluded.
This led to a few `.svg` with missing or bit-rotted expectations, which
have now been added/updated.
2024-02-18 18:33:11 +01:00
MacDue
b10f58a1fe LibWeb: Support x and y attributes on nested SVGs
This allows positioning a child SVG relative to its parent SVG.

Note: These have been implemented as CSS properties as in SVG 2, these
are geometry properties that can be used in CSS (see
https://www.w3.org/TR/SVG/geometry.html), but there is not much browser
support for this. It is nicer to implement than the ad-hoc SVG
attribute parsing though, so I feel it may make sense to port the rest
of the attributes specified here (which should fix some issues with
viewport relative sizes).
2024-01-29 10:01:10 +00:00
MacDue
5cf1570f40 LibWeb: Add initial support for nesting SVG viewports
Previously, we were handling viewBoxes/viewports in a slightly hacky
way, asking graphics elements to figure out what viewBox to use during
layout. This does not work in all cases, and can't allow for more
complex SVGs where it is possible to have nested viewports.

This commit makes the SVGFormattingContext keep track of the
viewport/boxes, and it now lays out each viewport recursively, where
each nested `<svg>` or `<symbol>` can establish a new viewport.

This fixes some previous edge cases, and starts to allow nested
viewports (there's still some issues to resolve there).

Fixes #22931
2024-01-27 18:12:13 +01:00
Aliaksandr Kalenik
de32b77ceb LibWeb: Use separate structure to represent fragments in paintable tree
This is a part of refactoring towards making the paintable tree
independent of the layout tree. Now, instead of transferring text
fragments from the layout tree to the paintable tree during the layout
commit phase, we allocate separate PaintableFragments that contain only
the information necessary for painting. Doing this also allows us to
get rid LineBoxes, as they are used only during layout.
2024-01-13 10:53:38 +01:00
Andreas Kling
e7de5cb4d2 LibWeb: Bring CSS line-height closer to other engines
This patch makes a few changes to the way we calculate line-height:

- `line-height: normal` is now resolved using metrics from the used
  font (specifically, round(A + D + lineGap)).

- `line-height: calc(...)` is now resolved at style compute time.

- `line-height` values are now absolutized at style compute time.

As a consequence of the above, we no longer need to walk the DOM
ancestor chain looking for line-heights during style computation.
Instead, values are inherited, resolved and absolutized locally.

This is not only much faster, but also makes our line-height metrics
match those of other engines like Gecko and Blink.
2024-01-12 15:04:06 +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
2753075830 LibWeb: Do not crash when svg mask calculation failed
Currently `calculate_mask()` fails to create bitmap when
`maskContentUnits="objectBoundingBox"` is present.

Fixes https://github.com/SerenityOS/serenity/issues/22316
2023-12-16 19:48:36 +01:00