Add support for temporary storage via a new config option
`temporary_storage`
and a corresponding command-line argument `--temporary-storage`.
When enabled, client storage uses a storage directory
(e.g. `clientstorage/temporary/<uuid>`) instead of the shared default
location.
This can be used to provide isolation between concurrent servo
instances.
This is especially useful for WPT runs, where multiple Servo instances
may
execute in parallel and would otherwise share the same storage, leading
to
cross-test interference.
Based on that, this PR also updates the WPT runner to enable temporary
storage
by default.
Testing: Manual testing and a full try run.
Signed-off-by: Jan Varga <jvarga@igalia.com>
Update jni-rs to 0.22, the main changes involve the introduction of
`with_env` within native methods, and updating uses of
`attach_current_thread`, which now requires a closure passed to it.
Callback object is now stored inside a `OnceLock`, since it would crash
when it was deleted, probably once a `WakeupCallback` was dropped:
```
JNI DETECTED ERROR IN APPLICATION: JNI ERROR (app bug): jobject is an invalid global reference: 0x2fc6 (deleted reference at index 382)
```
Also update android-activity and rustls-platform-verifier.
Testing: We don't have android tests in CI, manual testing is required
Fixes: Part of #40979
---------
Signed-off-by: Gae24 <96017547+Gae24@users.noreply.github.com>
Follow-up to #44443.
This helps investigating the cold-start timeline, and could be used
by tooling to A/B compare branches affecting the cold-start time.
Additionally also change the `handle_request::select` span, so that we
can see the blocked time (which was probably what was intended), since
the actual time spent on recv after select is insignificant.
Testing: Tracing output is not covered by automatic tests.
---------
Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
Adds a profiling event at the startup of servoshell, right after
initializing the tracing subsystem. To support this, add macro
abstractions for tracing events.
The existing span (macros) have a start and an end, but for one-off
events, we don't need a span and hence it make sense to also add the
event macros.
The new event at startup is useful when measuring / optimizing general
startup time. Adding a timestamp as field, allows us to ground the
measurement and compare it against time measured outside of servo,
regardless of how the profiling backend (tracing-perfetto,
tracing-hitrace, future backends) save timestamps.
Testing: Build-testing: the HarmonyOS build enables the tracing feature.
On other platforms this is not the case in CI.
---------
Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
Bumps [bpaf](https://github.com/pacak/bpaf) from 0.9.24 to 0.9.25.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pacak/bpaf/blob/master/Changelog.md">bpaf's
changelog</a>.</em></p>
<blockquote>
<h2>bpaf [0.9.25] - 2026-04-15</h2>
<ul>
<li>Change rendering of an adjacent block in Markdown - this is no
longer a <code>###</code>
but a regular line item instead. Header messes up with generated
navigation on
some pages</li>
<li><code>app_name</code> - parser that extracts the executable
name</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/pacak/bpaf/commits/v0.9.25">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Add the Storage Standard WebIDL for NavigatorStorage and StorageManager,
wire navigator.storage on Window and Worker, and implement persisted(),
persist(), and estimate().
Testing: covered by WP test.
part of #39100fixes#39101
---------
Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
This change introduces the `accessibility_tree` module, containing code
to build an in-memory representation of a very basic accessibility tree
for web contents. Currently, the tree for a given document contains:
- a `RootWebArea` which has the document root node as its sole child,
- an `Unknown` node for the root DOM node,
- a `GenericContainer` node for each DOM element, and
- a `TextRun` node for each text node.
This allows us to make basic assertions about the tree contents in the
`accessibility` test by doing a tree walk to find text nodes and
checking their contents.
Right now, the tree is rebuilt from scratch when accessibility is
enabled and when a navigation occurs (via
`Constellation::set_frame_tree_for_webview()` sending
`ScriptThreadMessage::SetAccessibilityActive`); it's not responsive to
changes in the page.
This change also changes the way we handle updating the graft node
between the webview's accessibility tree and its top level pipeline's
accessibility tree.
Previously, `Constellation::set_frame_tree_for_webview()` would send a
`ConstellationToEmbedderMsg::DocumentAccessibilityTreeIdChange` method
informing the webview of the accesskit TreeId of the top-level pipeline.
However, this resulted in flaky timing as we couldn't depend on that
message being handled before the message containing the TreeUpdate from
the WebContents, which would lead to a panic as the new TreeId wasn't
grafted into the combined tree yet.
This change introduces an epoch value which flows from the
ConstellationWebview, where it's updated every time the
`active_top_level_pipeline_id` changes, to the layout accessibility
tree, and finally to the webview with each TreeUpdate. Whenever a
TreeUpdate arrives at the webview which has a newer epoch than the last
known epoch, the webview-to-contents graft node is updated before the
TreeUpdate is forwarded. If a TreeUpdate arrives at the webview with an
epoch _older_ than the last known epoch, it's dropped, as it must be for
a no-longer-active pipeline.
Fixes: Part of #4344
---------
Signed-off-by: delan azabani <dazabani@igalia.com>
Signed-off-by: Alice Boxhall <alice@igalia.com>
Co-authored-by: delan azabani <dazabani@igalia.com>
Co-authored-by: Luke Warlow <lwarlow@igalia.com>
The upgrade to egui 0.34.0 in #44053 replaced the usage of the
deprecated `Ui::available_rect` method with `Ui::content_rect` as
suggested in the deprecation notice in egui. However, `content_rect` is
not equivalent to `available_rect` and doesn't seem to account for the
area occupied by the egui panels.
Since `content_rect` returns the window's inner dimensions, we don't ask
the webview to resize itself to the correct dimension that excludes the
toolbar (tabs and url). We also pass the correct dimension to egui's
paint callback, which meant that the WebView appeared vertically
squashed.
Fix this by using `available_rect_before_wrap` method instead of
`content_rect`. This seems to return the correct area that we need for
the WebView's dimenstion. The code in egui also seems closer to what we
want as it relies on a cursor that is advanced after each widget is
added. However, I'm not sure in which scenario the wrapping matters as
there is no documentation for this method.
Testing: Tested manually as we don't have automated tests for the shell.
Fixes: #44136
Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
Configured fonts for Linux referring to the same pattern used for
Windows in #44055.
CJK font files are loaded from standard system font paths, trying
Noto Sans CJK (Ubuntu/Debian and Fedora/Arch paths) with WenQuanYi
Micro Hei as a fallback. Fonts that are not present on the system
are silently skipped.
Testing: Loaded `cjk_test.html` with the following content in servoshell
on Linux:
```html
<!DOCTYPE html>
<html>
<head>
<title>ご利用ガイド - 경애하는</title>
</head>
<body>
<p>Test</p>
</body>
</html>
Before: Tab title showed boxes (□□□□ - □□□□)
After: Tab title renders correctly (ご利用ガイド - 경애하는)
```
Fixes part of #44066
---------
Signed-off-by: CynthiaOketch <cynthiaoketch6@gmail.com>
Testing: We have no automated testing for the servoshell UI. Some quick
manual testing of servo.org seemed to work as expected.
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
The macro `impl_from_pref!` would cause panic in this case.
Testing: Add more test cases to existing UT.
Fixes: #44078
---------
Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
Implement drop-down select multiple:
- Updates the embedder API to support multi-selects.
- Updates the select element to correctly reset when multiple attribute
is removed.
- Select now renders "n selected" as button text when more than 1, or 0
options are selected.
Note that listbox selects are not yet supported, once they are these new
features will be for `<select multiple size=1>`.
Testing: WPTs and also manually using
https://demo.lukewarlow.dev/css-forms.html. The two test regressions are
due to the lack of listbox support rather than an issue with this PR.
Fixes: #38509
---------
Signed-off-by: Luke Warlow <lwarlow@igalia.com>
Signed-off-by: Martin Robinson <martin@abandonedwig.info>
Co-authored-by: Martin Robinson <martin@abandonedwig.info>
Instead of panicking when pressing a keyboard shortcut for an uknown
WebView, just silently ignore the request. This code path is only
followed when using keyboard shortcuts, so this isn't going to hide any
unexpected behavior.
Testing: We do not have testing at this level of servoshell.
Fixes: #44056.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Testing: We do not currently have a way to test signal handling in the
servoshell binary, so this change does not include tests.
Fixes: #43836
---------
Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
Servo may hide and show IME when handling `blur` and `focus` events, but
those events can be fired asynchronously when `<iframe>`s are involved.
This change ensures that we only dismiss the IME when it was the
most-recently opened one, making it so that an asynchronously fired
'blur' event for another control doesn't dismiss a newly opened one.
Testing: We don't really have testing for this level of servoshell.
Signed-off-by: Martin Robinson <mrobinson@fastmail.fm>
Co-authored-by: Martin Robinson <mrobinson@fastmail.fm>
We receive the `Ime::Disabled` event both when the user dismisses the
IME and
when Servo itself dismisses it (for instance, when changing focus on the
page).
Servo will blur the current element upon receiving
`ImeEvent::Dismissed`,
leading to spurious focus behavior. Address this by only sending this
message
to Servo when it was triggered by the user (as best as we can tell).
This
problem was revealed by improvements in the internal focus APIs.
This is a bit of a bandaid until we have a more robust IME API. There
are
still missing pieces in both Servo and in winit.
Testing: This is a bit tricky to test as it depends a lot on when
messages are
sent to servoshell from winit / the windowing system and when Servo
processes
focus events.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
this patch plumbs the webview accessibility trees (#43029, #43556) into
servoshell. we add a global flag in servoshell, which is set when the
platform activates accessibility and cleared when the platform
deactivates accessibility. the flag in turn [activates
accessibility](https://doc.servo.org/servo/struct.WebView.html#method.set_accessibility_active)
in existing and new webviews.
Testing: none in this patch, but will be covered by end-to-end platform
a11y tests in WPT
Fixes: part of #4344, extracted from our work in #42338
Signed-off-by: delan azabani <dazabani@igalia.com>
Co-authored-by: Luke Warlow <lwarlow@igalia.com>
Co-authored-by: Alice Boxhall <alice@igalia.com>
In preparation for the next release, bump the version number to 0.1. 0.1
will be an LTS release, which receives extended support in terms of
security updates (e.g. spidermonkey security updates). Please keep in
mind that as always no specific guarantees or response times are given,
and any updated are provided on a best effort basis.
Previously some projects had a demo integration of servo based on some
version of servo, and then never or rarely updated it. Providing an LTS
release offers an option to embedders to integrate servo, while reducing
API churn and having a somewhat fixed schedule to adhere to in terms of
upgrades. Currently, the plan is for a new LTS release every 6 months,
with additional documentation regarding API changes and recommended
migration patterns (best-effort and subject to change).
Testing: No functional changes. Additional testing will be performed
post-merge on the newly created release branch.
Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
This PR considers the following constraints:
- Resources must be available when building servo via a published
crates.io package (i.e. no `../../../resources/<file>` file references).
- Minimal setup when writing tests (`nextest` spawns each test in its
own process, so we don't want to explicitly initialize the resource
handler for every `#[test]` fn)
- Use local resources when developing locally
- Support loading the resources from a proper resource directory if the
embedder wishes so, including via a custom mechanism, not necessarily as
files
(File) Resources that are only accessed from servoshell are out of scope
of this PR, since it mainly focusses on unblocking publishing `libservo`
to crates.io.
Baking the resources into the binary by default simplifies the setup a
lot. We already supported that before, but only for testing purposes and
explicitly not for production builds.
Using [`inventory`](https://crates.io/crates/inventory) adds a simple
way for the embedder to replace the default baked in resources, while
also keeping the test usage of baked in resources simple.
rippy.png is also referenced from image_cache - We simply duplicate it,
since the image is small, to avoid adding unnecessarily complex
solutions like adding a dedicated crate.
Testing: Covered by existing tests. [mach try
full](https://github.com/jschwe/servo/actions/runs/23811669469)
Fixes: Part of #43145
---------
Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
This change has 2 parts:
- adding `BluetoothPickDeviceRequest`, similar to other request structs
used to communicate with the embedder.
- switch from a `Vec<String>` that expected 2 * <device count> strings
to `Vec<BluetoothDeviceDescription>` which is easier to reason about.
Testing: Manual testing with a build that has the `native-bluetooth`
feature enabled.
---------
Signed-off-by: webbeef <me@webbeef.org>
- canvas
- constellation_traits
- canvas_traits
- constellation
Testing: This should not change any behaviour.
---------
Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
btleplug depends on tokio so we use a bridge thread to interface with
Servo thread based messaging.
We keep feature parity except for BtleplugGATTService::get_includes()
that will require upstream implementation.
In terms of OS support, I verified on Linux and MacOS. Android is
untested, but btleplug claims support.
Testing: No test failures, green try run at
https://github.com/webbeef/servo/actions/runs/23390850825Fixes: #43254.
Signed-off-by: webbeef <me@webbeef.org>
Follow up of #43526. This addresses Nico's comment:
https://github.com/servo/servo/pull/43526#issuecomment-4104953308
- `bluetooth_traits` -> `servo_bluetooth_traits`
- `base` -> `servo_base`
- `bluetooth` -> `servo_bluetooth`
- `background_hang_monitor` -> `servo_background_hang_monitor`
Testing: This should not change any behaviour.
---------
Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
Found when building with Rust 1.94. The lint itself only complains about
the direct function ptr to usize cast and recommends an intermediate `as
*const ()` cast. We also don't need provenance here, so we can also use
the more explicit .addr() cast.
Testing: Covered by compilation in CI.
Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
This fixes a warning of `cargo publish`:
```
warning: manifest has no description, documentation, homepage or repository
```
Testing: Compiling. Manual testing of `cargo publish --dry-run` (with
some additional patches, and until the next error, shows this warning
has been fixed)
Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
Previously the `pinch_zoom` method on `WebView` would be used to update
the page's pinch zoom level, however there was no way for the embedder
to retrieve the current pinch zoom.
This patch renames the existing `pinch_zoom` method to
`adjust_pinch_zoom` and changes the `pinch_zoom` method to instead
return the current pinch zoom level.
---
Decided to go for the breaking change since I'd find `pinch_zoom`
combined with `get_pinch_zoom` to be confusing, however I'm happy to
change that if a non-breaking change is preferred.
Motivation for this patch is just that I'd like to display the zoom
level in my UI while rendering.
Testing: Since this change adds a simple getter to the API, we can
probably avoid a unit test in this case.
---------
Signed-off-by: Christian Duerr <contact@christianduerr.com>
Bumps [bpaf](https://github.com/pacak/bpaf) from 0.9.23 to 0.9.24.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pacak/bpaf/blob/master/Changelog.md">bpaf's
changelog</a>.</em></p>
<blockquote>
<h2>bpaf [0.9.24] - 2026-03-13</h2>
<ul>
<li>
<p>a less confusing error message when invalid user input mixes with
parsers that
can succeed with no input, see <a
href="https://redirect.github.com/pacak/bpaf/issues/442">#442</a>
thanks <a href="https://github.com/tonky"><code>@tonky</code></a> for a
solution prototype</p>
</li>
<li>
<p>CI test for older rustc now uses 1.71, MSRV should still be 1.60 for
now</p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/pacak/bpaf/commits">compare view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
In preparation for a release to crates.io, bump the workspace version to
match the current servoshell version, and let the servoshell version use
the workspace version again. This makes versioning for us easier, and
makes more sense since servoshell is considered to be just a demo for
servo.
The `./mach release` command is updated to support bumping the workspace
version, and patch the version requirement of all workspace-versioned
workspace dependencies.
Testing: Can be manually verified by running `./mach release
<new_version>`. Note that this just bumps the version numbers, and
doesn't release anything, so it's perfectly safe to run.
---------
Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
I noticed while investigating #42636 that whenever servoshell displays a
link target URL, the associated tooltip is sometimes shown with some
kind of transparency, that is usually - but not always - "fixed" after a
bit of time.
The first problem is that we create the tooltip in the background, while
we should put it on top of everything else. This is however not
sufficient to fix the "flickering", hence the explicit call to
set_needs_repaint, like was done for dialogs in 6d4937b5d6.
Testing: manual (servoshell's visual aspects not covered by any test)
Fixes: https://github.com/servo/servo/issues/42636
Signed-off-by: Simon Martin <simon@nasilyan.com>
In order to prepare for publishing this PR does the following steps (see
commits):
- Move all `path` dependencies to the workspace Cargo.toml, and
reference that.
- Move all path dependencies in the workspace Cargo.toml into a
dedicated section, to make bumping version numbers easier later.
- Add the version requirement. Note that we currently only version bump
servoshell. There was agreement to version everything with the same
version as servoshell, but that be done in a follow-up. The diff is
already large enough as is.
- Add a tidy lint to catch `path` usages outside the root Cargo.toml. I
switched to [`tomllib`] (which was added to the python stdlib in 3.11),
since the third-party `toml` library failed to parse Cargo.toml files
with `workspace.version` (did not like the `.` in a `key`).
[`tomllib`]: https://docs.python.org/3/library/tomllib.html
Testing: Should be covered by regular CI testing.
---------
Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
This makes the name of the `GamepadDelegate` consistent with the other
delegates.
Testing: No tests necessary as this is just renaming some structs and
members. Compilation should be enough.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This option controls whether progressive web metrics are printed to the
system console, which is essentially the purpose of
`DiagnosticsLogging`. This makes the API a bit more uniform.
Testing: We do not really have automated testing for this kind of
feature of the API.
Fixes: This is part of #34967.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This change makes it so that all of these things are set on the
`WebView` via the `WebViewBuilder`. This does make it impossible to
change the delegate after the `WebView` is constructed, but that does
mean that we can now count on that fact internally in Servo. This change
just seeks to standardize the way that these kind of structs are given
to Servo to make the API easier to understand.
Testing: There aren't currently tests for the clipboard delegate, but
this
change should work as the corresponding parts in servoshell still
compile.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This setting is used to control whether or not incremental legacy layout
was enabled. Nowadays incremental layout is always enabled as it is a
fundamental feature of how layout works. The setting also controls
whether or not nodes are traversed in Style, but that's also something
that's much less interesting today. This change just removes this
setting as it just controls the Stylo setting. A corresponding change in
Stylo will also remove the setting there.
Testing: This just removes a setting so existing tests should suffice.
Fixes: This is part of #34967.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This concept does not need to be exposed to `Opts` any longer as it just
controls how servoshell uses the `WebView` API.
Testing: A successful compilation is enough here as this is just moving
an option.
Fixes: This is part of #34967.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
As discussed on zulip we would like to rename `libservo` to `servo`
(again) before a future crates.io release.
Servo is a library, so the `lib` prefix is somewhat redundant. We
already renamed the binary of ServoShell to `servoshell`, to reduce
confusion of users of what servo is.
Note: This PR does not touch all occurrences of `libservo`. Specifically
CI job names remain untouched, since the risk of breaking something is
higher here, harder to test for and the name not user facing.
Testing: CI testing of this change should give us good confidence.
Manual testing of `./mach doc` and `./mach build` showed no issues on
macos. [Full try
run](https://github.com/jschwe/servo/actions/runs/22909562747)
Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
Fixed a typo in the comment documentation in
`ports/servoshell/prefs.rs`. Changed "arugment" to "argument" on line
291.
Testing: This change does not need testing because it just fixes a typo
in a rustdoc comment.
Signed-off-by: hobostay <110hqc@gmail.com>
This message appeared in a backtrace without any format replacement
taking place.
Testing: No tests for error messages.
---------
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
We had two `Info.plist` files. The maintained one is in the root
directory of this repository.
There is no reason for two plist files, so remove the unmaintained one.
Additionally, we also move the maintained version from the root
directory to the servoshell directory.
Testing: We don't test the contents of the plist file.
---------
Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
Because of the move of the reporting function to
update_user_interface_state and the multiple events of
LoadStatus::Complete, the previous reporting did not work correctly
anymore.
This fixes it by manually summing up the reports for
'resident-according-to-smaps' and using the hitrace-bencher
point_filter_type Largest.
This should restore the bencher graph.
Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
Testing: No automatic test but manual test here:
https://github.com/Narfinger/servo/actions/runs/22617931816
Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>