This moves Servo closer to the focus parts of the HTML specification.
The behavior should be the same as before, but now the code in `script`
matches the structure of the specification.
The main goal is to set us up for:
- Firing focus events in the right order on nested documents
- A proper implementation of the unfocusing steps.
Testing: This should not change behavior so is covered by existing
tests.
Signed-off-by: Martin Robinson <mrobinson@fastmail.fm>
Co-authored-by: Martin Robinson <mrobinson@fastmail.fm>
Instead of readily adding a strut for text carets when processing a line
break, wait until a line is finished. This allows placing a strut on the
final line. In addition to fixing #41338 this will also make it possible
to handle line breaks as a separate kind of text run item so that we can
preserve shaping results between layouts.
In addition, some changes are made in script to ensure that these
placeholders
are never placed for non-textual input elements.
Testing: This change adds a Servo-specific WPT test. Caret rendering
isn't specified.
Fixes: #41338
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Switch the remaining `SafeJSContext` usages to `&mut JSContext` inside
script_module.rs
Testing: It compiles.
Part of #40600
---------
Signed-off-by: Gae24 <96017547+Gae24@users.noreply.github.com>
This brings up to date with the specification for declarative shadow
roots: https://github.com/whatwg/html/pull/12267.
The `shadowrootslotassignment` attribute on `<template>` elements
specifies the slot assignment mode used by the declarative shadow root
created by the template.
Testing: New tests start to pass
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
Drop the `ModuleOwner` logic in favour of closures passed down by the
script fetching initiator.
When processing inline module scripts a task in now queued on the
networking task source. Since `Rc<ModuleTree>` is not `Send`, a `result`
field is now introduced to `HTMLScriptElement`, which is initialized
before queueing the task.
This slightly improves `inline-async-inserted-execorder.html`, which now
fails at the fourth assertion instead of stopping at the second one (the
inline module script with no dependencies still resolves after the one
that has a parse error).
Testing: Covered by existing tests.
---------
Signed-off-by: Gae24 <96017547+Gae24@users.noreply.github.com>
This removes some complains that clippy will have in 1.95.
As this is mostly just match guards, it doesn't update MSRV.
Testing: This is equivalent exchanges, so current WPT would find
anything.
---------
Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
Previously the code was computing a prefix sum over the number of
preceding elements in tree order to get the index that the node should
be inserted in.
That's not great if the DOM tree is big. Instead, we can compare two
nodes individually by looking at their ancestor chain and then find the
correct position with binary search.
On https://262.ecma-international.org/16.0/index.html, this reduces the
time it takes for content to appear from around 33s to 16s.
Part of https://github.com/servo/servo/issues/44113
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
Refactor AudioContext methods to use &mut JSContext
Testing: Just refactor.
Fixes: Part of #42638
---------
Signed-off-by: Emmanuel Paul Elom <elomemmanuel007@gmail.com>
When mutating window-reflecting event handler attributes on <body>,
HTMLBodyElement::attribute_mutated forwarded handlers to owner_window()
even for documents without a browsing context.
This caused handlers such as onload to be attached to the wrong window
in cases involving createHTMLDocument() and node cloning.
Only forward these handlers when the owner document has a browsing
context. This matches the has_browsing_context() check used by
window_event_handlers!(ForwardToWindow) and the spec algorithm.
The Range WPT expectations added for this issue are removed, as those
tests now pass. The onerroreventhandler.html test is marked as TIMEOUT
as its failure is a separate issue tracked in #44157 .
Testing:
- ./mach fmt
- ./mach test-tidy
- ./mach test-wpt -r dom/ranges
- ./mach test-wpt -r
html/webappapis/scripting/events/onerroreventhandler.html
- ./mach try linux-wpt ( Try run
[#24328414549](https://github.com/arabson99/servo/actions/runs/24328414549))
Reproduced locally with the parent.html/child.html testcase from #36561.
Before this change, Servo logged "foo is not defined".
After this change, the error no longer appears.
Fixes: #36561
Signed-off-by: arabson99 <arabiusman99@gmail.com>
The parsed relations of a element don't depend on its position in the
DOM tree at all, so this does nothing.
Testing: This should not change observable behaviour, WPT should catch
regressions
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
Servo has had two implementations of `selectors::Element`, one used
during layout and one used for `Element#matches()` and
`Element#closest()`. The DOM APIs can trivially use the version that's
exposed to the layout interface, which allows removing the duplicated
implementation. This will eliminate code and prevent the two
implementations from drifting apart.
Testing: This should not change behavior in a testable way so should
be covered by existing tests.
Signed-off-by: Martin Robinson <mrobinson@fastmail.fm>
Co-authored-by: Martin Robinson <mrobinson@fastmail.fm>
This change reworks the layout DOM wrappers so that they are simpler and
easier to reason about. The main changes here:
**Combine layout wrappers into one interface:**
- `LayoutNode`/`ThreadSafeLayoutNode` is combined into `LayoutNode`:
The idea here is that `LayoutNode` is always thread-safe when used in
layout as long as no `unsafe` calls are used. These interfaces
only expose what is necessary for layout.
- `LayoutElement`/`ThreadSafeLayoutElement` is combined into
`LayoutElement`: See above.
**Expose two new interfaces to be used *only* with `stylo` and
`selectors`:**
`DangerousStyleNode` and `DangerousStyleElement`. `stylo`
and `selectors` have a different way of ensuring safety that is
incompatible with Servo's layout (access all of the DOM tree anywhere,
but ensure that writing only happens from a single-thread). These types
only implement things like `TElement`, `TNode` and are not intended to
be used by layout at all.
All traits and implementations are moved to files that are named after
the struct or trait inside them, in order to better understand what one
is looking at.
The main goals here are:
- Make it easier to reason about the safe use of the DOM APIs.
- Remove the interdependencies between the `stylo` and `selectors`
interface implementations and the layout interface. This helps
with the first point as well and makes it simpler to know where
a method is implemented.
- Reduce the amount of code.
- Make it possible to eliminate `TrustedNodeAddress` in the future.
- Document and bring the method naming up to modern Rust conventions.
This is a lot of code changes, but is very well tested by the WPT tests.
Unfortunately, it is difficult to make a change like this iteratively.
In addition, this new design comes with new documentation at
servo/book#225.
Testing: This should not change behavior so should be covered by
existing
WPT tests.
Signed-off-by: Martin Robinson <mrobinson@fastmail.fm>
Make Servo match the focus bits of the HTML specification a bit more by
storing a `FocusableArea` as the currently focused thing in a
`Document` instead of an optional `Element`. There is always a focused
area of a `Document`, defaulting to the viewport. This is important to
support the case of focused navigables and image maps parts in the
future.
Some focus chain debugging code has been removed as the focus chain
concept needs to be reworked to match the specification more closely.
Testing: This should not change behavior so existing tests should
suffice.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
I noticed that the transferFromImageBitmap() was running without errors
but the canvas stayed blank and this was becacuse of two issues:
The mark_as_dirty was empty meaning the canvas never knew it needed to
repaint
The BitmapRenderer context had no rendering pipeline as such no ImageKey
was allocated and update_rendering always returned false, so the way I
fixed it is by
1. Implemented mark_as_dirty to call self.canvas.mark_as_dirty()
2. Allocated an ImageKey for BitmapRenderer contexts
3.Implemented set_image_key and update_rendering that sends the bitmap's
pixel data to WebRender via the paint API
4, Calling mark_as_dirty after set_bitmap in TransferFromImageBitmap
Now the reason we are setting an ImageKey on the
ImageBitmaRenderingContext is because it needs one to render to the
screen and without it the canvas was always blank
Also I noticed that for some reasons I don't understand yet, the
createImageBitmap hangs or is slow to render but after loading servo on
an open tab, if I then go ahead and open another tab and paste the file
link there, the previous tab which had the bitmap image now renders
properly
Fixes: #43565
<img width="383" height="238" alt="Screenshot from 2026-04-06 13-44-28"
src="https://github.com/user-attachments/assets/4c5096ba-ee84-4e7a-a3c6-673cc12276c4"
/>
<img width="389" height="292" alt="Screenshot from 2026-04-06 15-38-55"
src="https://github.com/user-attachments/assets/43b45e60-61d8-48de-b53e-6da5ab988768"
/>
Signed-off-by: Messi002 <rostandmessi2@gmail.com>
Servo has lots of `LayoutXYZHelper` traits that are used to define
additional methods on `LayoutDom<XYZ>`. We can replace them with `impl
LayoutDom<XYZ>` blocks, reducing the number of LoC and making it easier
to add or modify methods.
Testing: These should be covered by existing tests
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
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>
Refer to https://github.com/servo/servo/pull/43746 for a description of
the problem. This change ensures that video posters can be loaded from
blob URLs, even if the URL is revoked right after.
Testing: This change adds a test
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
Implement Player Trait in ohos backend using Harmony OS MediaKit's[
AVPlayer](https://developer.huawei.com/consumer/en/doc/harmonyos-references/capi-avplayer-h).
The modular design of `VideoSink`, `InnerPlayer`, and `MediaSource` is
taken from the GStreamer backend.
Only support HarmonyOS SDK API 21, because the
`OH_AVPlayer_SetDataSource` only started to be exposed on API 21.
Testing: N/A, as there are no platform specific task.
Fixes: N/A, now we can play video on HarmonyOS phone using `<video>`
---------
Signed-off-by: rayguo17 <rayguo17@gmail.com>
Removed ```introduction_type_override``` field from
```HTMLScriptElement``` & passed the new variable to
```fetch_inline_module_script```
Testing: No testing required, compiles successfully.
Fixes: #43980
Signed-off-by: Sabb <sarafaabbas@gmail.com>
`blob` URLs have a implicit blob URL entry attached, which stores the
data contained in the blob. The specification requires this entry to be
resolved as the URL is parsed. We only resolve it inside `net` when
loading the URL. That causes problems if the blob entry has been revoked
in the meantime - see https://github.com/servo/servo/issues/25226.
Ideally we would want to resolve blobs at parse-time as required. But
because `ServoUrl` is such a fundamental type, I've not managed to do
this change without having to touch hundreds of files at once.
Thus, we now require passing a `UrlWithBlobClaim` instead of a
`ServoUrl` when `fetch`-ing. This type proves that the caller has
acquired the blob beforehand.
As a temporary escape hatch, I've added
`UrlWithBlobClaim::from_url_without_having_claimed_blob`. That method
logs a warning if its used unsafely. This method is currently used in
most places to keep this change small. Only workers now acquire the blob
beforehand.
Testing: A new test starts to pass
Part of https://github.com/servo/servo/issues/43326
Part of https://github.com/servo/servo/issues/25226
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
Co-authored-by: Josh Matthews <josh@joshmatthews.net>
Implement render-blocking option for script fetch and load events
## Testing:
### Test summary on main branch
```bash
▶ OK [expected CRASH] /html/semantics/scripting-1/the-script-element/moving-between-documents/move-back-createHTMLDocument-success-external-module.html
Ran 470 tests finished in 217.9 seconds.
• 453 ran as expected.
• 4 tests crashed unexpectedly
• 1 tests timed out unexpectedly
• 11 tests unexpectedly okay
• 2 tests had unexpected subtest results
/home/elomscansio/.local/share/uv/python/cpython-3.11.15-linux-x86_64-gnu/lib/python3.11/multiprocessing/resource_tracker.py:254: UserWarning: resource_tracker: There appear to be 3 leaked semaphore objects to clean up at shutdown
warnings.warn('resource_tracker: There appear to be %d '
```
### Test summary for this commits
```bash
Ran 470 tests finished in 488.0 seconds.
• 397 ran as expected.
• 15 tests crashed unexpectedly
• 27 tests timed out unexpectedly
• 11 tests unexpectedly okay
• 28 tests had unexpected subtest results
```
Fixes: #43697Fixes: #43354
---------
Signed-off-by: Emmanuel Paul Elom <elomemmanuel007@gmail.com>
Signed-off-by: elomscansio <163124154+elomscansio@users.noreply.github.com>
Signed-off-by: Gae24 <96017547+Gae24@users.noreply.github.com>
Co-authored-by: Gae24 <96017547+Gae24@users.noreply.github.com>
A lot (and I mean, really a lot) depends on these constructors.
Therefore, this is the one spaghetti ball that I could extract and
convert all `can_gc` to `cx`. There are some new introductions of
`temp_cx` in the callbacks of the servo parser, but we already had some
in other callbacks.
Part of #40600
Testing: It compiles
Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
We support these setting these as attributes on the `<table>` element
itself, so I suppose it also makes sense to support their DOM APIs as
well. This trades a teensy bit of code for compatability with a some old
web content.
Testing: This causes a handful of reflection subtests to start passing.
There
isn't much testing for the behavior of the attributes, but this is
legacy
behavior so it sort of makes sense.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
The specification says that `:focus` should be active on all shadow
hosts of ancestors of focused areas. This change does that by exposing a
new `DocumentFocusHandler::set_focused_element` method and also using it
during the "removing steps." This is important because unlike the
"focusing steps" `set_focused_element` does not cause focus and blur
events.
Testing: This leads to a progression in results on 8 WPT tests.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This continues the work to split up the large DOM structs. In this case
we create a helper struct to store focus-related state much like
`DocumentEventHandler`.
Testing: This is mostly code motion, so should be covered by existing
tests.
Fixes: #43720
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
`DocumentOrShadowRoot#activeElement` should return retargeted results.
What that means is that if the DOM anchor of the `Document`'s focused
focusable area is within a shadow root, `Document#activeElement` should
return the shadow host. This change implements that behavior, properly
returning the `activeElement` from both `Document` and `ShadowRoot`.
Testing: This causes a decent number of WPT tests and subtests to start
passing. One subtest starts to fail, because it uses the `autofocus`
attribute
which we do not yet support.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
When navigating to a fragment the specification says to run the focusing
steps. This is possible now that the focusing steps are properly
exposed. This change also adds support for the fallback option, which is
used when the focus target is not associated with a focuable area. In
this case the fallback is to focus the viewport.
Testing: This change adds a new WPT for this behavior, which was
seemingly not tested before.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
`HTMLOrSVGElement#focus` specifies the "scroll into view" steps should
be run after focusing. This was happening implicitly as part of the
`Document`'s implementation of the "focusing steps." That behavior is
not in the specification, so this change moves the scrolling call to
where it is specified. Along with making the code match the
specification, this change simplifies it as well.
Testing: This should not modify behavior, so existing tests should
suffice.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
For years Servo has had the concept of a focus transaction which was
used only to allow falling back to focusing the viewport when focusing a
clicked element failed. As this concept isn't part of the specification,
this change removes it.
Instead, a `FocusableArea` (a specification concept) is passed to
the `Document` focusing code. A `FocusableArea` might also be the
`Document`'s viewport.
As part of this change, some focus-related methods are moved to `Node`
from `Element` as the `Document` is not an `Element`. This brings the
code closer to implementing the "focusing steps" from the specification.
Testing: This should not change behavior and is thus covered by existing
tests.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
In addition to making it so that textual `<input>` and `<textarea>`
share a common shadow DOM structure, this allows styling the
`<textarea>` placeholder. It is now properly shown in grey.
Testing: This fixes a few WPT tests.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
upcast::<Type>() is costly in general, but in some cases we can avoid
that call and use a direct field access instead.
Testing: no test change expected.
Signed-off-by: webbeef <me@webbeef.org>
This set of changes introduces a type matching the spec's "target
snapshot params" and uses it as part of determining the origin of new
documents. This has a side benefit of making our sandbox flag
determination more accurate, which leads to a bunch of sandboxing tests
passing as well as some new failures due to spec confusion about
origins.
Testing: Many new passing tests.
Part of the long road to #43149
---------
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This change has two main interdependent parts:
1. It starts to align Servo's focus code with what is written in the
HTML specification. This is going to be a gradual change, so there
are still many parts that do not match the specification yet. Still,
this adds the major pieces.
2. It adds initial support for the `ShadowRoot.delegatesFocus` property
which controls how focusing a shadow DOM root can delegate focus to
one of its children.
Testing: This causes a few WPT tests to start passing.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Implement the layout of `<input type="range">`. Support automatically
calculating the position of thumb based on the current input value, and
the size of range-track and range-thumb. Added a
document.has_script_or_layout_blocker function to detect whether it is
possible to run box_area_query during bind_to_tree, add delay_task if
there are blocker.
Here are some of the fixes made in this PR:
1. Fixed the structure for input type range's pseudo elements.
2. Fixed the positioning of input type range's thumb based on current
value, width, and direction.
3. Allow input type range to stretch vertically in a bigger container.
Original PR: #41024
Stylo PR: https://github.com/servo/stylo/pull/310
Testing: Some improvements in WPT tests, with a few regressions. This
change includes a Servo-specific appearance test to detect unexpected
changes to the look and feel of range widgets.
Fixes: #22728
---------
Signed-off-by: Budiman Arbenta <arbenta6@gmail.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: rayguo17 <tin.tun.aung1@huawei.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
Also move the related `navigate_to_fragment` method next to it.
Part of #40600
Testing: It compiles
Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
Both `Window::load_url` and `ScriptThread::navigate` implement parts of
the same navigate algorithm from the HTML spec
(https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate).
`ScriptThread::navigate` had only one caller: `Window::load_url`.
This merges both methods into a single `navigate` function in
`navigation.rs`, which is the appropriate home for navigation logic. All
previous callers of `Window::load_url` now call `navigation::navigate`
directly.
Testing: This is a pure refactor with no behaviour changes, so no new
tests are needed. Existing tests cover the navigation paths affected.
Fixes: #43494
---------
Signed-off-by: thebabalola <t.babalolajoseph@gmail.com>
The commit contains several related changes:
* iframes that load javascript: URLs as part of the initial insertion
(ie. `<iframe src='javascript:...'>`) get a synchronous load event
dispatched
* javascript: URL evaluation that does not result in a string no longer
treated like a 204 response
* iframes that perform a javascript: URL navigation that does not result
in a new document no longer block the parent document load event
Testing: Lots of new tests passing.
Fixes: #24901
---------
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This adds the WebIDl and implementation for the HTMLMarqueeElement type.
The `<marquee>` HTML is now assigned this type.
None of the contained properties or methods are implemented yet.
Testing: Existing WPTs
Signed-off-by: Luke Warlow <lwarlow@igalia.com>