script: propagate VirtualMethods::unbind_from_tree with &mut JSContext (#44422)

Propagate `&mut JSContext` in `VirtualMethods::unbind_from_tree`

Testing: Successful build is enough
Fixes: #42837

---------

Signed-off-by: Emmanuel Paul Elom <elomemmanuel007@gmail.com>
This commit is contained in:
elomscansio
2026-04-23 15:09:11 +01:00
committed by GitHub
parent ff0e9655a8
commit aa7eca43b7
25 changed files with 71 additions and 92 deletions

View File

@@ -4509,14 +4509,14 @@ impl VirtualMethods for Element {
}
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
self.super_type().unwrap().unbind_from_tree(context, can_gc);
fn unbind_from_tree(&self, cx: &mut JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
if let Some(f) = self.as_maybe_form_control() {
// TODO: The valid state of ancestors might be wrong if the form control element
// has a fieldset ancestor, for instance: `<form><fieldset><input>`,
// if `<input>` is unbound, `<form><fieldset>` should trigger a call to `update_validity()`.
f.unbind_form_control_from_tree(can_gc);
f.unbind_form_control_from_tree(CanGc::from_cx(cx));
}
if !context.tree_is_in_a_document_tree && !context.tree_is_in_a_shadow_tree {
@@ -4527,17 +4527,17 @@ impl VirtualMethods for Element {
let fullscreen = doc.fullscreen_element();
if fullscreen.as_deref() == Some(self) {
doc.exit_fullscreen(can_gc);
doc.exit_fullscreen(CanGc::from_cx(cx));
}
if let Some(ref value) = *self.id_attribute.borrow() {
if let Some(ref shadow_root) = self.containing_shadow_root() {
// Only unregister the element id if the node was disconnected from it's shadow root
// (as opposed to the whole shadow tree being disconnected as a whole)
if !self.upcast::<Node>().is_in_a_shadow_tree() {
shadow_root.unregister_element_id(self, value.clone(), can_gc);
shadow_root.unregister_element_id(self, value.clone(), CanGc::from_cx(cx));
}
} else {
doc.unregister_element_id(self, value.clone(), can_gc);
doc.unregister_element_id(self, value.clone(), CanGc::from_cx(cx));
}
}
if let Some(ref value) = self.name_attribute() {

View File

@@ -21,7 +21,6 @@ use crate::dom::html::htmlelement::HTMLElement;
use crate::dom::node::{BindContext, Node, NodeTraits, UnbindContext};
use crate::dom::security::csp::CspReporting;
use crate::dom::virtualmethods::VirtualMethods;
use crate::script_runtime::CanGc;
#[dom_struct]
pub(crate) struct HTMLBaseElement {
@@ -177,8 +176,8 @@ impl VirtualMethods for HTMLBaseElement {
document.refresh_base_element();
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
self.super_type().unwrap().unbind_from_tree(context, can_gc);
fn unbind_from_tree(&self, cx: &mut JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
// https://html.spec.whatwg.org/multipage/#frozen-base-url
// > The base element becomes the first base element in tree order with an href content attribute in its Document.
let document = self.owner_document();

View File

@@ -418,8 +418,8 @@ impl VirtualMethods for HTMLButtonElement {
.check_ancestors_disabled_state_for_form_control();
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
self.super_type().unwrap().unbind_from_tree(context, can_gc);
fn unbind_from_tree(&self, cx: &mut JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
let node = self.upcast::<Node>();
let el = self.upcast::<Element>();

View File

@@ -534,8 +534,8 @@ impl VirtualMethods for HTMLDetailsElement {
self.ensure_details_exclusivity(ExclusivityConflictResolution::CloseThisElement);
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
self.super_type().unwrap().unbind_from_tree(context, can_gc);
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
if context.tree_is_in_a_document_tree && !self.upcast::<Node>().is_in_a_document_tree() {
self.owner_document()

View File

@@ -1324,7 +1324,7 @@ impl VirtualMethods for HTMLElement {
/// <https://html.spec.whatwg.org/multipage#dom-trees:concept-node-remove-ext>
///
/// TODO: These are the node removal steps, so this should be done for all Nodes.
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
// 1. Let document be removedNode's node document.
let document = self.owner_document();
@@ -1354,7 +1354,7 @@ impl VirtualMethods for HTMLElement {
// corresponding HTML element removing steps given removedNode, isSubtreeRoot, and
// oldAncestor.
if let Some(super_type) = self.super_type() {
super_type.unbind_from_tree(context, can_gc);
super_type.unbind_from_tree(cx, context);
}
// 4. If removedNode is a form-associated element with a non-null form owner and removedNode

View File

@@ -1883,8 +1883,8 @@ impl VirtualMethods for HTMLFormElement {
Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
self.super_type().unwrap().unbind_from_tree(context, can_gc);
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
// Collect the controls to reset because reset_form_owner
// will mutably borrow self.controls
@@ -1901,7 +1901,7 @@ impl VirtualMethods for HTMLFormElement {
control
.as_maybe_form_control()
.expect("Element must be a form control")
.reset_form_owner(can_gc);
.reset_form_owner(CanGc::from_cx(cx));
}
}

View File

@@ -16,7 +16,6 @@ use js::rust::HandleObject;
use net_traits::ReferrerPolicy;
use net_traits::request::Destination;
use profile_traits::ipc as ProfiledIpc;
use script_bindings::script_runtime::temp_cx;
use script_traits::{NewPipelineInfo, UpdatePipelineIdReason};
use servo_base::id::{BrowsingContextId, PipelineId, WebViewId};
use servo_constellation_traits::{
@@ -1239,15 +1238,11 @@ impl VirtualMethods for HTMLIFrameElement {
}
/// <https://html.spec.whatwg.org/multipage/#the-iframe-element:html-element-removing-steps>
#[expect(unsafe_code)]
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
self.super_type().unwrap().unbind_from_tree(context, can_gc);
// TODO: https://github.com/servo/servo/issues/42837
let mut cx = unsafe { temp_cx() };
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
// The iframe HTML element removing steps, given removedNode, are to destroy a child navigable given removedNode
self.destroy_child_navigable(&mut cx);
self.destroy_child_navigable(cx);
self.owner_document().invalidate_iframes_collection();
}

View File

@@ -2131,15 +2131,9 @@ impl VirtualMethods for HTMLImageElement {
}
}
#[expect(unsafe_code)]
/// <https://html.spec.whatwg.org/multipage/#the-img-element:html-element-removing-steps>
fn unbind_from_tree(&self, context: &UnbindContext, _can_gc: CanGc) {
// TODO: https://github.com/servo/servo/issues/42837
let mut cx = unsafe { temp_cx() };
let cx = &mut cx;
self.super_type()
.unwrap()
.unbind_from_tree(context, CanGc::from_cx(cx));
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
let document = self.owner_document();
document.unregister_responsive_image(self);

View File

@@ -18,7 +18,6 @@ use crate::dom::html::htmlfieldsetelement::HTMLFieldSetElement;
use crate::dom::html::htmlformelement::{FormControl, HTMLFormElement};
use crate::dom::node::{BindContext, Node, UnbindContext};
use crate::dom::virtualmethods::VirtualMethods;
use crate::script_runtime::CanGc;
#[dom_struct]
pub(crate) struct HTMLLegendElement {
@@ -70,8 +69,8 @@ impl VirtualMethods for HTMLLegendElement {
.check_ancestors_disabled_state_for_form_control();
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
self.super_type().unwrap().unbind_from_tree(context, can_gc);
fn unbind_from_tree(&self, cx: &mut JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
let node = self.upcast::<Node>();
let el = self.upcast::<Element>();

View File

@@ -484,9 +484,9 @@ impl VirtualMethods for HTMLLinkElement {
}
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
if let Some(s) = self.super_type() {
s.unbind_from_tree(context, can_gc);
s.unbind_from_tree(cx, context);
}
self.remove_stylesheet();

View File

@@ -3418,8 +3418,8 @@ impl VirtualMethods for HTMLMediaElement {
}
/// <https://html.spec.whatwg.org/multipage/#playing-the-media-resource:remove-an-element-from-a-document>
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
self.super_type().unwrap().unbind_from_tree(context, can_gc);
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
self.remove_controls();

View File

@@ -26,7 +26,6 @@ use crate::dom::html::htmlelement::HTMLElement;
use crate::dom::html::htmlheadelement::HTMLHeadElement;
use crate::dom::node::{BindContext, Node, NodeTraits, UnbindContext};
use crate::dom::virtualmethods::VirtualMethods;
use crate::script_runtime::CanGc;
#[dom_struct]
pub(crate) struct HTMLMetaElement {
@@ -257,9 +256,9 @@ impl VirtualMethods for HTMLMetaElement {
self.process_referrer_attribute();
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
if let Some(s) = self.super_type() {
s.unbind_from_tree(context, can_gc);
s.unbind_from_tree(cx, context);
}
if context.tree_connected {

View File

@@ -147,13 +147,13 @@ impl VirtualMethods for HTMLOptGroupElement {
self.update_select_validity(CanGc::from_cx(cx));
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
self.super_type().unwrap().unbind_from_tree(context, can_gc);
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
if let Some(select) = context.parent.downcast::<HTMLSelectElement>() {
select
.validity_state(can_gc)
.perform_validation_and_update(ValidationFlags::all(), can_gc);
.validity_state(CanGc::from_cx(cx))
.perform_validation_and_update(ValidationFlags::all(), CanGc::from_cx(cx));
}
}
}

View File

@@ -469,8 +469,8 @@ impl VirtualMethods for HTMLOptionElement {
self.update_select_validity(CanGc::from_cx(cx));
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
self.super_type().unwrap().unbind_from_tree(context, can_gc);
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
if let Some(select) = context
.parent
@@ -478,8 +478,8 @@ impl VirtualMethods for HTMLOptionElement {
.find_map(DomRoot::downcast::<HTMLSelectElement>)
{
select
.validity_state(can_gc)
.perform_validation_and_update(ValidationFlags::all(), can_gc);
.validity_state(CanGc::from_cx(cx))
.perform_validation_and_update(ValidationFlags::all(), CanGc::from_cx(cx));
select.ask_for_reset();
}

View File

@@ -1310,8 +1310,8 @@ impl VirtualMethods for HTMLScriptElement {
}
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
self.super_type().unwrap().unbind_from_tree(context, can_gc);
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
if self.marked_as_render_blocking.replace(false) {
let document = self.owner_document();

View File

@@ -867,8 +867,8 @@ impl VirtualMethods for HTMLSelectElement {
.check_ancestors_disabled_state_for_form_control();
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
self.super_type().unwrap().unbind_from_tree(context, can_gc);
fn unbind_from_tree(&self, cx: &mut JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
let node = self.upcast::<Node>();
let el = self.upcast::<Element>();

View File

@@ -34,7 +34,6 @@ use crate::dom::node::{
ShadowIncluding, UnbindContext,
};
use crate::dom::virtualmethods::VirtualMethods;
use crate::script_runtime::CanGc;
/// <https://html.spec.whatwg.org/multipage/#the-slot-element>
#[dom_struct]
@@ -511,9 +510,9 @@ impl VirtualMethods for HTMLSlotElement {
}
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
if let Some(s) = self.super_type() {
s.unbind_from_tree(context, can_gc);
s.unbind_from_tree(cx, context);
}
if !self.upcast::<Node>().is_in_a_shadow_tree() {

View File

@@ -6,7 +6,6 @@ use dom_struct::dom_struct;
use html5ever::{LocalName, Prefix, local_name};
use js::context::JSContext;
use js::rust::HandleObject;
use script_bindings::script_runtime::temp_cx;
use style::attr::AttrValue;
use crate::dom::attr::Attr;
@@ -23,7 +22,6 @@ use crate::dom::html::htmlmediaelement::HTMLMediaElement;
use crate::dom::html::htmlpictureelement::HTMLPictureElement;
use crate::dom::node::{BindContext, Node, NodeDamage, UnbindContext};
use crate::dom::virtualmethods::VirtualMethods;
use crate::script_runtime::CanGc;
#[dom_struct]
pub(crate) struct HTMLSourceElement {
@@ -175,15 +173,9 @@ impl VirtualMethods for HTMLSourceElement {
}
}
#[expect(unsafe_code)]
/// <https://html.spec.whatwg.org/multipage/#the-source-element:html-element-removing-steps>
fn unbind_from_tree(&self, context: &UnbindContext, _can_gc: CanGc) {
// TODO: https://github.com/servo/servo/issues/42837
let mut cx = unsafe { temp_cx() };
let cx = &mut cx;
self.super_type()
.unwrap()
.unbind_from_tree(context, CanGc::from_cx(cx));
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
// Step 1. If oldParent is a picture element, then for each child of oldParent's children,
// if child is an img element, then count this as a relevant mutation for child.

View File

@@ -347,9 +347,9 @@ impl VirtualMethods for HTMLStyleElement {
self.update_a_style_block();
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
if let Some(s) = self.super_type() {
s.unbind_from_tree(context, can_gc);
s.unbind_from_tree(cx, context);
}
// https://html.spec.whatwg.org/multipage/#update-a-style-block

View File

@@ -684,8 +684,8 @@ impl VirtualMethods for HTMLTextAreaElement {
}
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
self.super_type().unwrap().unbind_from_tree(context, can_gc);
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
let node = self.upcast::<Node>();
let el = self.upcast::<Element>();
@@ -698,8 +698,8 @@ impl VirtualMethods for HTMLTextAreaElement {
el.check_disabled_attribute();
}
self.validity_state(can_gc)
.perform_validation_and_update(ValidationFlags::all(), can_gc);
self.validity_state(CanGc::from_cx(cx))
.perform_validation_and_update(ValidationFlags::all(), CanGc::from_cx(cx));
}
// The cloning steps for textarea elements must propagate the raw value

View File

@@ -2194,9 +2194,9 @@ impl VirtualMethods for HTMLInputElement {
self.value_changed(CanGc::from_cx(cx));
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
fn unbind_from_tree(&self, cx: &mut JSContext, context: &UnbindContext) {
let form_owner = self.form_owner();
self.super_type().unwrap().unbind_from_tree(context, can_gc);
self.super_type().unwrap().unbind_from_tree(cx, context);
let node = self.upcast::<Node>();
let el = self.upcast::<Element>();
@@ -2209,12 +2209,15 @@ impl VirtualMethods for HTMLInputElement {
el.check_disabled_attribute();
}
self.input_type()
.as_specific()
.unbind_from_tree(self, form_owner, context, can_gc);
self.input_type().as_specific().unbind_from_tree(
self,
form_owner,
context,
CanGc::from_cx(cx),
);
self.validity_state(can_gc)
.perform_validation_and_update(ValidationFlags::all(), can_gc);
self.validity_state(CanGc::from_cx(cx))
.perform_validation_and_update(ValidationFlags::all(), CanGc::from_cx(cx));
}
// This represents behavior for which the UIEvents spec and the

View File

@@ -412,7 +412,7 @@ impl Node {
// This needs to be in its own loop, because unbind_from_tree may
// rely on the state of IS_IN_DOC of the context node's descendants,
// e.g. when removing a <form>.
vtable_for(node).unbind_from_tree(context, CanGc::from_cx(cx));
vtable_for(node).unbind_from_tree(cx, context);
// Step 12 & 14.2. Enqueue disconnected custom element reactions.
if is_parent_connected {
@@ -4759,8 +4759,8 @@ impl VirtualMethods for Node {
// This handles the ranges mentioned in steps 2-3 when removing a node.
/// <https://dom.spec.whatwg.org/#concept-node-remove>
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
self.super_type().unwrap().unbind_from_tree(context, can_gc);
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
// Ranges should only drain to the parent from inclusive non-shadow
// including descendants. If we're in a shadow tree at this point then the

View File

@@ -626,9 +626,9 @@ impl VirtualMethods for ShadowRoot {
}
}
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
if let Some(s) = self.super_type() {
s.unbind_from_tree(context, can_gc);
s.unbind_from_tree(cx, context);
}
if context.tree_connected {

View File

@@ -33,7 +33,6 @@ use crate::dom::node::{
};
use crate::dom::svg::svggraphicselement::SVGGraphicsElement;
use crate::dom::virtualmethods::VirtualMethods;
use crate::script_runtime::CanGc;
#[dom_struct]
pub(crate) struct SVGSVGElement {
@@ -258,9 +257,9 @@ impl VirtualMethods for SVGSVGElement {
self.invalidate_cached_serialized_subtree();
}
fn unbind_from_tree(&self, context: &UnbindContext<'_>, can_gc: CanGc) {
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext<'_>) {
if let Some(s) = self.super_type() {
s.unbind_from_tree(context, can_gc);
s.unbind_from_tree(cx, context);
}
let owner_window = self.owner_window();
self.owner_window()

View File

@@ -135,9 +135,9 @@ pub(crate) trait VirtualMethods {
/// Called when a Node is removed from a tree.
/// Implements removing steps:
/// <https://dom.spec.whatwg.org/#concept-node-remove-ext>
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
if let Some(s) = self.super_type() {
s.unbind_from_tree(context, can_gc);
s.unbind_from_tree(cx, context);
}
}