This change adds support for rendering static SVG images using the
`resvg` crate, allowing svg sources in the `img` tag and in CSS
`background` and `content` properties. There are some limitations in
using resvg:
1. There is no support for animations or interactivity as these would
require implementing the full DOM layer of SVG specification.
2. Only system fonts can be used for text rendering. There is some
mechanism to provide a custom font resolver to usvg, but that is not
explored in this change.
3. resvg's handling of certain edge cases involving lack of explicit
`width` and `height` on the root svg element deviates from what the
specification expects from browsers. For example, resvg uses the values
in `viewBox` to derive the missing width or height dimension, but
without scaling that dimension to preserve the aspect ratio. It also
doesn't allow overriding this behavior.
Demo screenshot:

<details>
<summary>Source</summary>
```
<style>
#svg1 {
border: 1px solid red;
}
#svg2 {
border: 1px solid red;
width: 300px;
}
#svg3 {
border: 1px solid red;
width: 300px;
height: 200px;
object-fit: contain;
}
#svg4 {
border: 1px solid red;
width: 300px;
height: 200px;
object-fit: cover;
}
#svg5 {
border: 1px solid red;
width: 300px;
height: 200px;
object-fit: fill;
}
#svg6 {
border: 1px solid red;
width: 300px;
height: 200px;
object-fit: none;
}
</style>
</head>
<body>
<div>
<img id="svg1" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo">
</div>
<div>
<img id="svg2" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo">
<img id="svg3" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo">
<img id="svg4" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo">
</div>
<div>
<img id="svg5" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo">
<img id="svg6" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo">
</div>
</body>
```
</details>
---------
Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This change adds a shadow-tree widget for `<input type=color>` elements.
It also involves some changes to the way layout interacts with the DOM,
because currently all `input` and `textarea` elements are rendered as
plain text and their descendants are ignored. This obviously doesn't
work for `<input type={color, date, range, etc}>`.

<details><summary>HTML used for the screenshot above</summary>
```html
<input type=color>
```
</details>
Testing: I doubt that this affects WPT tests, because the appearance and
behaviour of the widget is almost entirely unspecified.
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
This is the last big change necessary to create the
`constellation_traits` crate. This moves the data structure for messages
that originate from the `ScriptThread` and are sent to the
`Contellation` to `constellation_traits`, effectively splitting
`script_traits` in half. Before, `script_traits` was responsible for
exposing the API of both the `ScriptThread` and the `Constellation` to
the rest of Servo.
- Data structures that are used by `ScriptToConstellationMsg` are moved
to `constellation_traits`. The dependency graph looks a bit like this:
`script_layout_interface` depends on `script_traits` depends on
`constellation_traits` depends on `embedder_traits`.
- Data structures that are used in the embedding layer
(`UntrustedNodeAddress`, `CompositorHitTestResult`, `TouchEventResult`
and `AnimationState`) are moved to embedder_traits, to avoid a
dependency cycle between `webrender_traits` and
`constellation_traits`.
- Types dealing with MessagePorts and serialization are moved to
`constellation_traits::message_port`.
Testing: This is covered by existing tests as it just moves types
around.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix#35390
- [X] There are tests for these changes
[Successful WPT
run](1409767962)
(which includes the new test files)
(I didn't make the formatting changes intentionally--those came from
`mach format` following `mach test-tidy`.)
---------
Signed-off-by: Michael Rees <mrees@noeontheend.com>
- Remove the last remaining Servo-specific PseudoElement enum from
layout. This was made to select `::before` and `::after` (both eager
pseudo-elements), but now `traverse_pseudo_element` is called
`traverse_eager_pseudo_element` and should work on any eager pseudo
element.
- Expose a single way of getting psuedo-element variants of
ThreadSafeLayoutElement in the Layout DOM, which returns `None` when
the pseudo-element doesn't apply (not defined for eager
pseudo-elements or when trying to get `<details>` related
pseudo-elements on elements that they don't apply to).
- Ensure that NodeAndStyleInfo always refers to a node. This is done by
making sure that anonymous boxes are all associated with their
originating node.
These changes are prepatory work for implementation of the `::marker`
pseudo-element as well as ensuring that all anonymous boxes can be
cached into the box tree eventually.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Servo has a `PseudoElementType` which more or less duplicate's Stylo's
`PseudoElement` with the addition of a non-pseudo element variant. This
type needs to be converted into `PseudoElement` anyway when asking for
the style of an element from Stylo, so eliminate Servo's version and
simply use `Option<PseudoElement>` with the `None` variant meaning the
non-pseudo.
This is preparation for adding support for the `::marker` pseudo
element.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This change creates a `constellation_traits` crate. Previously messages
to the `Constellation` were in the `compositing_traits` crate, which
came about organically. This change moves these to a new crate which
also contains data types that are used in both compositing/libservo and
script (ie types that cross the process boundary). The idea is similar
to `embedding_traits`, but this is meant for types not exposed to the
API.
This change allows deduplicating `UntrustedNodeAddress`, which
previously had two versions to avoid circular dependencies.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This is now unused with the removal of legacy layout. I didn't see any
others methods in this trait that were unused.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
* Use 2024 style edition
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Reformat all code
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Allow attaching UA shadow roots to any element
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Implement a UA shadow tree for the <meter> element
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Add UA styles for the meter element
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Include spec text when computing meter state
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
This fixes common crash related to slottables, currently present on wpt.fyi.
Previously, the traversal parent of `Text` nodes was incorrectly
assumed to always be the parent or shadow host. That caused crashes
inside stylo's bloom filter. Now the traversal parent is the slot
that the node is assigned to, if any, and the parent/shadow host otherwise.
The slottable data for Text/Element nodes is now stored in NodeRareData.
This is very cheap, because NodeRareData will already be instantiated
for assigned slottables anyways, because the containing_shadow_root
field will be set (since assigned slottables are always in a shadow
tree). This change is necessary because we need to hand out references
to the assigned slot to stylo and that is not possible to do (without
unsafe code) if we need to downcast the node first.
As a side effect, this reduces the size of `Text` from 256 to 232 bytes,
because the slottable data is no longer stored there.
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Make Slottable match layout/alignment of NonNull<Node>
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Implement ServoLayoutElement::slotted_nodes
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Bump mozjs
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Layout the contents of slot elements
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Implement ServoLayoutElement::assigned_slot
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* implement ServoLayoutElement::traversal_parent
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Simplify slottable name update
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Don't iterate over children of shadow hosts
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Recompute slot style when contents change
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Change match_slottable to a function instead of a macro
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Fix crown errors
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Update WPT expectations
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Reset a slottable's assigned slot when it's removed from the slot
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
There is some interesting history to this change:
* https://github.com/servo/servo/issues/33495: Servo crashes on
Cloudflare's turnstile, because we didn't compute style for
elements inside shadow trees
* https://github.com/servo/servo/pull/34298: Resolves the issue
by computing style for children of a potential shadow root,
in addition to the children of an element
* https://github.com/servo/servo/pull/34701: Changes layout
of elements with shadow roots such that only the contents
of the shadow root are laid out
Now, we compute style for both the children of the element
and a potential shadow root, but only lay out the contents
of the shadow tree (if there is one).
This behaviour is not technically incorrect,
since regular children are not included in layout
their style doesn't matter. However, it is
inefficient: the only case where we need to compute
style for a child of a shadow host is when
that child is an assigned slottable in a slot
somewhere else.
This part 1/n of upstreaming the changes necessary
to lay out `<slot>` contents. Note that trying to compute
style for `<slot>` contents *and* children of shadow hosts
will crash in stylo, since it expects to see each
element only once.
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Rename IS_IN_DOC flag to IS_IN_A_DOCUMENT_TREE
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Add BindContext::is_in_a_shadow_tree
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Add UnbindContext::tree_is_in_shadow_tree
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* ./mach fmt
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Update test expectations
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* fix build after rebasing
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
The new version of rust allows us to elide some lifetimes and clippy is
now complaining about this. This change elides them where possible and
removes the clippy exceptions.
Fixes#34804.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
The `pending reflow` concept isn't necessary now that *update the
rendering* is taking care of triggering reflows at the correct time.
`Window::reflow` already avoids reflows if the page is not dirty, so
pending reflows is now just an extraneous check as long as *update the
rendering* runs properly.
This change also removes some explicit reflows, which now wait until the
appropriate moment during *update the rendering*. This should remove
some extra reflows that are not necessary.
Servo needs some way to track that resizing the web view needs to
re-layout due to the initial containing block changing. Move handling
of `Document::needs_paint` to the script thread and use this, expanding
the rustdoc to explain what it is for a bit more clearly.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
* Include non-shadowdom children of shadow hosts in style calculation
This was previously causing crashes because the layout nodes
of those children would never be assigned style data by stylo.
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Update WPT expectations
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
This change:
1. Adds safety documentation where it was missing.
2. Limits the scope of unsafe code in some cases to where it is actually
unsafe.
3. Converts some free functions to associated functions and methods,
thereby making them more likely to be called safely.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
* Upgrade stylo to 2024-07-16
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
* Use the new `dom` crate from stylo
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
---------
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This crate only takes care of fonts now as graphics related things are
split into other crates. In addition, this exposes data structures at
the top of the crate, hiding the implementation details and making it
simpler to import them.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Mukilan Thiyagarajan <mukilan@igalia.com>
* layout: Take into account `display: table` etc in offset* queries
The specification says that for deciding whether an element should be
used for offset* queries, a browser should take into account whether the
element is a table cell or table. This change makes that happen.
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
* Only tag HTML elements if they are in the HTML namespace
---------
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
* Move WebRender related types to `webrender_traits`
This refactor moves several WebRender related types
from `compositing_traits`, `script_traits` and `net_traits`
crates to the `webrender_traits` crate.
This change also moves the `Image` type and associated
function out of `net_traits` and into the `pixels` crate.
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
* Move `script_traits::WebrenderIpcSender` to `webrender_traits::WebRenderScriptApi`
---------
Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
For a long time, `gfx_traits` has held a lot of things unrelated to graphics
and also unrelated to the `gfx` crate (which is mostly about fonts).
This is a cleanup which does a few things:
1. Move non `gfx` crate things out of `gfx_traits`. This is important in
order to prevent dependency cycles with a different integration between
layout, script, and fonts.
2. Rename the `msg` crate to `base`. It didn't really contain anything
to do with messages and instead mostly holds ids, which are used
across many different crates in Servo. This new crate will hold the
*rare* data types that are widely used.
Details:
- All BackgroundHangMonitor-related things from base to a new
`background_hang_monitor_api` crate.
- Moved `TraversalDirection` to `script_traits`
- Moved `Epoch`-related things from `gfx_traits` to `base`.
- Moved `PrintTree` to base. This should be widely useful in Servo.
- Moved `WebrenderApi` from `base` to `webrender_traits` and renamed it
to `WebRenderFontApi`.
Bumps Stylo to servo/stylo#37
`white-space` is split into `white-space-collapse` and `text-wrap-mode`:
| white-space | white-space-collapse | text-wrap-mode |
| ----------- | -------------------- | -------------- |
| normal | collapse | wrap |
| nowrap | collapse | nowrap |
| pre-wrap | preserve | wrap |
| pre | preserve | nowrap |
| pre-line | preserve-breaks | wrap |
| - | preserve-breaks | nowrap |
Note this introduces a combination that wasn't previously possible,
but I think the existing logic can handle it well enough.
The old `allow_wrap()` is replaced by checking whether `text-wrap-mode`
is set to `wrap`.
The old `preserve_newlines()` is replaced by checking whether
`white-space-collapse` is *not* set to `collapse`.
The old `preserve_spaces()` is replaced by checking whether
`white-space-collapse` is set to `preserve`.
Remove the type parameter from the layout DOM wrappers. This is possible
now that style and layout data are separate and the `Any` nature of the
layout data is exposed in the wrappers.
Removing the phantom data member of the wrappers also allows using the
default `derive` implementations for things like `Clone`, `Copy`, and
`PartialEq`.
This change splits the style and layout data in DOM nodes that is
populated by style and layout passes. This makes Servo's data design
more like Gecko's. This allows:
1. Removing the various `StyleAndLayout` data structures used by layout.
2. Removing the `GetStyleAndLayoutData` and
`GetStyleAndOpaqueLayoutData` traits. Accessing style and layout data
are now just functions on the `LayoutNode` and `ThreadSafeLayoutNode`
traits.
3. Styling now doesn't populate layout data. This is is postponed until
layout itself.
4. Allows the DOM wrappers to no longer have to be generic over the
layout data. This data was already stored using `std::any::Any` and
the new code just makes layout responsible for downcasting. Cleaning
up the generic type parameter in the DOM wrappers can happen in a
followup change.
The main benefit to all of this is that we should be able to remove
unsafe creation of `ServoLayoutNode` in layout and
`TrustedLayoutNodeAddress` entirely, because `ServoLayoutNode` will be
able to be passed directly from script to layout. In addition, this
removes one more abstraction layer from the layout DOM wrappers, making
the code a lot more understandable.
Note: This increases the measured size of DOM types, but the same data
is stored. It's simply that before that data was stored behind a heap
pointer.
Remove the use of unsafe code in the layout wrappers of the DOM. The
main change here is that `unsafe_get()` no longer needs to be an unsafe
method, which allows us to transitively remove or reduce unsafe blocks
from callers. The function itself is not renamed, because it's still
a bit dangerous to start removing the layers of abstraction from actual
DOM nodes.
In addition `init_style_and_opaque_layout_data` can be merged into
`initialize_data`, which removes one more unsafe method.
Finally, a "Safety" section is added to some unsafe methods.
* Fixd some clippy warnings in components/script
* Update node.rs
Removed the ```# Safety ``` section.
* Update shadow_root.rs
Removed the ``` # Safety ``` section from components/script/layout_dom
* Updated fixes to some clippy warnings in components/script
* Revert "Updated fixes to some clippy warnings in components/script"
This reverts commit 2a37c3dec8.
* Updated fixes to clippy warnings in components/script
* Revert "Updated fixes to clippy warnings in components/script"
This reverts commit 5780dc3a0a.
* Revert "Revert "Updated fixes to some clippy warnings in components/script""
This reverts commit 98c411354a.
* Revert "Updated fixes to some clippy warnings in components/script"
This reverts commit 2a37c3dec8.
* Update shadow_root.rs (Ignore change)
* Update node.rs (Ignore changes)
* Updated fixes to clippy warnings in components/script
* Removed trailing white space in componets/script/layout_dom_root.rs
* Revert "Removed trailing white space in componets/script/layout_dom_root.rs"
This reverts commit 1976fd0405.
* Revert "Updated fixes to clippy warnings in components/script"
This reverts commit 5c71b925fb.
* Updated fixes to clippy warnings in components/script including review suggestions.
* clippy: Fix `match_like_matches` warnings
* Fix link to custom element state in specification.
---------
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
In quirks mode, preserved segment breaks should add line height to
lines. This matches the behavior of WebKit and Blink, but not Gecko.
This also handles the special-case of `<br>` elements, which are
implemented with preserved segment breaks via `white-space: pre-line`.
This is an implementation detail though because `<br>` has a special
behavior if the line isn't empty -- it doesn't add any line height in
this case.