script: Pass &mut JSContext to VirtualMethods::cloning_steps and Node::clone (#43130)

Continuation of #43108, two new `temp_cx()` calls were required:
- inside `maybe_clone_an_option_into_selectedcontent` since it's part of
a markup5ever trait
- inside `serialize_and_cache_subtree` replacing a `CanGc::note()` call,
propagating it inside reflow code will require even more effort.

Testing: No behaviour change, a successful build is enough.
Part of #40600

---------

Signed-off-by: Gae24 <96017547+Gae24@users.noreply.github.com>
This commit is contained in:
Gae24
2026-03-10 18:05:34 +01:00
committed by GitHub
parent bc1cd2ceeb
commit 4ef22ed227
14 changed files with 163 additions and 111 deletions

View File

@@ -5606,9 +5606,9 @@ impl DocumentMethods<crate::DomTypeHolder> for Document {
/// <https://dom.spec.whatwg.org/#dom-document-importnode>
fn ImportNode(
&self,
cx: &mut js::context::JSContext,
node: &Node,
options: BooleanOrImportNodeOptions,
can_gc: CanGc,
) -> Fallible<DomRoot<Node>> {
// Step 1. If node is a document or shadow root, then throw a "NotSupportedError" DOMException.
if node.is::<Document>() || node.is::<ShadowRoot>() {
@@ -5638,7 +5638,7 @@ impl DocumentMethods<crate::DomTypeHolder> for Document {
// Step 7. Return the result of cloning a node given node with
// document set to this, subtree set to subtree, and fallbackRegistry set to registry.
Ok(Node::clone(node, Some(self), subtree, registry, can_gc))
Ok(Node::clone(cx, node, Some(self), subtree, registry))
}
/// <https://dom.spec.whatwg.org/#dom-document-adoptnode>

View File

@@ -2866,9 +2866,9 @@ impl Element {
/// Step 4 of <https://html.spec.whatwg.org/multipage/#dom-element-insertadjacenthtml>
/// and step 6. of <https://html.spec.whatwg.org/multipage/#dom-range-createcontextualfragment>
pub(crate) fn fragment_parsing_context(
cx: &mut JSContext,
owner_doc: &Document,
element: Option<&Self>,
can_gc: CanGc,
) -> DomRoot<Self> {
// If context is not an Element or all of the following are true:
match element {
@@ -2890,7 +2890,7 @@ impl Element {
ElementCreator::ScriptCreated,
CustomElementCreationMode::Asynchronous,
None,
can_gc,
CanGc::from_cx(cx),
),
}
}
@@ -4078,9 +4078,9 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
// Step 4.
let context = Element::fragment_parsing_context(
cx,
&context.owner_doc(),
context.downcast::<Element>(),
CanGc::from_cx(cx),
);
// Step 5: Let fragment be the result of invoking the
@@ -4824,13 +4824,13 @@ impl VirtualMethods for Element {
/// <https://html.spec.whatwg.org/multipage/#nonce-attributes%3Aconcept-node-clone-ext>
fn cloning_steps(
&self,
cx: &mut JSContext,
copy: &Node,
maybe_doc: Option<&Document>,
clone_children: CloneChildrenFlag,
can_gc: CanGc,
) {
if let Some(s) = self.super_type() {
s.cloning_steps(copy, maybe_doc, clone_children, can_gc);
s.cloning_steps(cx, copy, maybe_doc, clone_children);
}
let elem = copy.downcast::<Element>().unwrap();
if let Some(rare_data) = self.rare_data().as_ref() {

View File

@@ -552,7 +552,7 @@ fn split_the_parent<'a>(cx: &mut js::context::JSContext, node_list: &'a [&'a Nod
// Step 7. If the first child of original parent is not in node list:
if first_child_is_in_node_list {
// Step 7.1. Let cloned parent be the result of calling cloneNode(false) on original parent.
let Ok(cloned_parent) = original_parent.CloneNode(false, CanGc::from_cx(cx)) else {
let Ok(cloned_parent) = original_parent.CloneNode(cx, false) else {
unreachable!("Must always be able to clone node");
};
// Step 7.2. If original parent has an id attribute, unset it.

View File

@@ -3425,13 +3425,13 @@ impl VirtualMethods for HTMLInputElement {
/// <https://html.spec.whatwg.org/multipage/#the-input-element%3Aconcept-node-clone-ext>
fn cloning_steps(
&self,
cx: &mut JSContext,
copy: &Node,
maybe_doc: Option<&Document>,
clone_children: CloneChildrenFlag,
can_gc: CanGc,
) {
if let Some(s) = self.super_type() {
s.cloning_steps(copy, maybe_doc, clone_children, can_gc);
s.cloning_steps(cx, copy, maybe_doc, clone_children);
}
let elem = copy.downcast::<HTMLInputElement>().unwrap();
elem.value_dirty.set(self.value_dirty.get());
@@ -3441,7 +3441,7 @@ impl VirtualMethods for HTMLInputElement {
elem.textinput
.borrow_mut()
.set_content(self.textinput.borrow().get_content());
self.value_changed(can_gc);
self.value_changed(CanGc::from_cx(cx));
}
}

View File

@@ -200,7 +200,7 @@ impl HTMLOptionElement {
}
/// <https://html.spec.whatwg.org/multipage/#maybe-clone-an-option-into-selectedcontent>
pub(crate) fn maybe_clone_an_option_into_selectedcontent(&self, can_gc: CanGc) {
pub(crate) fn maybe_clone_an_option_into_selectedcontent(&self, cx: &mut JSContext) {
// Step 1. Let select be option's option element nearest ancestor select.
let select = self.nearest_ancestor_select();
@@ -213,33 +213,32 @@ impl HTMLOptionElement {
if let Some(selectedcontent) =
select.and_then(|select| select.get_enabled_selectedcontent())
{
self.clone_an_option_into_selectedcontent(&selectedcontent, can_gc);
self.clone_an_option_into_selectedcontent(cx, &selectedcontent);
}
}
}
/// <https://html.spec.whatwg.org/multipage/#clone-an-option-into-a-selectedcontent>
fn clone_an_option_into_selectedcontent(&self, selectedcontent: &Element, can_gc: CanGc) {
fn clone_an_option_into_selectedcontent(&self, cx: &mut JSContext, selectedcontent: &Element) {
// Step 1. Let documentFragment be a new DocumentFragment whose node document is option's node document.
let document_fragment = DocumentFragment::new(&self.owner_document(), can_gc);
let document_fragment = DocumentFragment::new(&self.owner_document(), CanGc::from_cx(cx));
// Step 2. For each child of option's children:
for child in self.upcast::<Node>().children() {
// Step 2.1 Let childClone be the result of running clone given child with subtree set to true.
let child_clone =
Node::clone(&child, None, CloneChildrenFlag::CloneChildren, None, can_gc);
let child_clone = Node::clone(cx, &child, None, CloneChildrenFlag::CloneChildren, None);
// Step 2.2 Append childClone to documentFragment.
let _ = document_fragment
.upcast::<Node>()
.AppendChild(&child_clone, can_gc);
.AppendChild(&child_clone, CanGc::from_cx(cx));
}
// Step 3. Replace all with documentFragment within selectedcontent.
Node::replace_all(
Some(document_fragment.upcast()),
selectedcontent.upcast(),
can_gc,
CanGc::from_cx(cx),
);
}
}

View File

@@ -1205,13 +1205,13 @@ impl VirtualMethods for HTMLScriptElement {
fn cloning_steps(
&self,
cx: &mut JSContext,
copy: &Node,
maybe_doc: Option<&Document>,
clone_children: CloneChildrenFlag,
can_gc: CanGc,
) {
if let Some(s) = self.super_type() {
s.cloning_steps(copy, maybe_doc, clone_children, can_gc);
s.cloning_steps(cx, copy, maybe_doc, clone_children);
}
// https://html.spec.whatwg.org/multipage/#already-started

View File

@@ -4,6 +4,7 @@
use dom_struct::dom_struct;
use html5ever::{LocalName, Prefix};
use js::context::JSContext;
use js::rust::HandleObject;
use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
@@ -132,31 +133,33 @@ impl VirtualMethods for HTMLTemplateElement {
/// <https://html.spec.whatwg.org/multipage/#the-template-element:concept-node-clone-ext>
fn cloning_steps(
&self,
cx: &mut JSContext,
copy: &Node,
maybe_doc: Option<&Document>,
clone_children: CloneChildrenFlag,
can_gc: CanGc,
) {
self.super_type()
.unwrap()
.cloning_steps(copy, maybe_doc, clone_children, can_gc);
.cloning_steps(cx, copy, maybe_doc, clone_children);
if clone_children == CloneChildrenFlag::DoNotCloneChildren {
// Step 1.
return;
}
let copy = copy.downcast::<HTMLTemplateElement>().unwrap();
// Steps 2-3.
let copy_contents = DomRoot::upcast::<Node>(copy.Content(CanGc::note()));
let copy_contents = DomRoot::upcast::<Node>(copy.Content(CanGc::from_cx(cx)));
let copy_contents_doc = copy_contents.owner_doc();
for child in self.Content(CanGc::note()).upcast::<Node>().children() {
for child in self.Content(CanGc::from_cx(cx)).upcast::<Node>().children() {
let copy_child = Node::clone(
cx,
&child,
Some(&copy_contents_doc),
CloneChildrenFlag::CloneChildren,
None,
CanGc::note(),
);
copy_contents.AppendChild(&copy_child, can_gc).unwrap();
copy_contents
.AppendChild(&copy_child, CanGc::from_cx(cx))
.unwrap();
}
}
}

View File

@@ -726,13 +726,13 @@ impl VirtualMethods for HTMLTextAreaElement {
// and dirty value flag from the node being cloned to the copy.
fn cloning_steps(
&self,
cx: &mut JSContext,
copy: &Node,
maybe_doc: Option<&Document>,
clone_children: CloneChildrenFlag,
can_gc: CanGc,
) {
if let Some(s) = self.super_type() {
s.cloning_steps(copy, maybe_doc, clone_children, can_gc);
s.cloning_steps(cx, copy, maybe_doc, clone_children);
}
let el = copy.downcast::<HTMLTextAreaElement>().unwrap();
el.value_dirty.set(self.value_dirty.get());
@@ -740,8 +740,8 @@ impl VirtualMethods for HTMLTextAreaElement {
let mut textinput = el.textinput.borrow_mut();
textinput.set_content(self.textinput.borrow().get_content());
}
el.validity_state(can_gc)
.perform_validation_and_update(ValidationFlags::all(), can_gc);
el.validity_state(CanGc::from_cx(cx))
.perform_validation_and_update(ValidationFlags::all(), CanGc::from_cx(cx));
}
fn children_changed(&self, mutation: &ChildrenMutation, can_gc: CanGc) {

View File

@@ -3471,11 +3471,11 @@ impl Node {
/// <https://dom.spec.whatwg.org/#concept-node-clone>
pub(crate) fn clone(
cx: &mut JSContext,
node: &Node,
maybe_doc: Option<&Document>,
clone_children: CloneChildrenFlag,
registry: Option<DomRoot<CustomElementRegistry>>,
can_gc: CanGc,
) -> DomRoot<Node> {
// Step 1. If document is not given, let document be nodes node document.
let document = match maybe_doc {
@@ -3493,7 +3493,7 @@ impl Node {
Some(doctype.public_id().clone()),
Some(doctype.system_id().clone()),
&document,
can_gc,
CanGc::from_cx(cx),
);
DomRoot::upcast::<Node>(doctype)
},
@@ -3507,17 +3507,17 @@ impl Node {
attr.namespace().clone(),
attr.prefix().cloned(),
None,
can_gc,
CanGc::from_cx(cx),
);
DomRoot::upcast::<Node>(attr)
},
NodeTypeId::DocumentFragment(_) => {
let doc_fragment = DocumentFragment::new(&document, can_gc);
let doc_fragment = DocumentFragment::new(&document, CanGc::from_cx(cx));
DomRoot::upcast::<Node>(doc_fragment)
},
NodeTypeId::CharacterData(_) => {
let cdata = node.downcast::<CharacterData>().unwrap();
cdata.clone_with_data(cdata.Data(), &document, can_gc)
cdata.clone_with_data(cdata.Data(), &document, CanGc::from_cx(cx))
},
NodeTypeId::Document(_) => {
// Step 1. Set copys encoding, content type, URL, origin, type, mode,
@@ -3552,7 +3552,7 @@ impl Node {
document.has_trustworthy_ancestor_or_current_origin(),
document.custom_element_reaction_stack(),
document.creation_sandboxing_flag_set(),
can_gc,
CanGc::from_cx(cx),
);
// Step 2. If nodes custom element registrys is scoped is true,
// then set copys custom element registry to nodes custom element registry.
@@ -3588,7 +3588,7 @@ impl Node {
ElementCreator::ScriptCreated,
CustomElementCreationMode::Asynchronous,
None,
can_gc,
CanGc::from_cx(cx),
);
// TODO: Move this into `Element::create`
element.set_custom_element_registry(registry);
@@ -3629,7 +3629,7 @@ impl Node {
attr.namespace().clone(),
attr.prefix().cloned(),
AttributeMutationReason::ByCloning,
can_gc,
CanGc::from_cx(cx),
);
}
},
@@ -3638,14 +3638,14 @@ impl Node {
// Step 5: Run any cloning steps defined for node in other applicable specifications and pass copy,
// node, document, and the clone children flag if set, as parameters.
vtable_for(node).cloning_steps(&copy, maybe_doc, clone_children, can_gc);
vtable_for(node).cloning_steps(cx, &copy, maybe_doc, clone_children);
// Step 6. If the clone children flag is set, then for each child child of node, in tree order: append the
// result of cloning child with document and the clone children flag set, to copy.
if clone_children == CloneChildrenFlag::CloneChildren {
for child in node.children() {
let child_copy = Node::clone(&child, Some(&document), clone_children, None, can_gc);
let _inserted_node = Node::pre_insert(&child_copy, &copy, None, can_gc);
let child_copy = Node::clone(cx, &child, Some(&document), clone_children, None);
let _inserted_node = Node::pre_insert(&child_copy, &copy, None, CanGc::from_cx(cx));
}
}
@@ -3670,7 +3670,7 @@ impl Node {
shadow_root.Serializable(),
shadow_root.DelegatesFocus(),
shadow_root.SlotAssignment(),
can_gc
CanGc::from_cx(cx),
)
.expect("placement of attached shadow root must be valid, as this is a copy of an existing one");
@@ -3681,11 +3681,11 @@ impl Node {
// cloning child with document and the clone children flag set, to copys shadow root.
for child in shadow_root.upcast::<Node>().children() {
let child_copy = Node::clone(
cx,
&child,
Some(&document),
CloneChildrenFlag::CloneChildren,
None,
can_gc,
);
// TODO: Should we handle the error case here and in step 6?
@@ -3693,7 +3693,7 @@ impl Node {
&child_copy,
copy_shadow_root.upcast::<Node>(),
None,
can_gc,
CanGc::from_cx(cx),
);
}
}
@@ -4311,7 +4311,7 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
}
/// <https://dom.spec.whatwg.org/#dom-node-clonenode>
fn CloneNode(&self, subtree: bool, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
fn CloneNode(&self, cx: &mut JSContext, subtree: bool) -> Fallible<DomRoot<Node>> {
// Step 1. If this is a shadow root, then throw a "NotSupportedError" DOMException.
if self.is::<ShadowRoot>() {
return Err(Error::NotSupported(None));
@@ -4319,6 +4319,7 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
// Step 2. Return the result of cloning a node given this with subtree set to subtree.
let result = Node::clone(
cx,
self,
None,
if subtree {
@@ -4327,7 +4328,6 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
CloneChildrenFlag::DoNotCloneChildren
},
None,
can_gc,
);
Ok(result)
}

View File

@@ -9,6 +9,7 @@ use std::iter;
use app_units::Au;
use dom_struct::dom_struct;
use euclid::Rect;
use js::context::JSContext;
use js::jsapi::JSTracer;
use js::rust::HandleObject;
use style_traits::CSSPixel;
@@ -596,7 +597,7 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
/// <https://dom.spec.whatwg.org/#dom-range-clonecontents>
/// <https://dom.spec.whatwg.org/#concept-range-clone>
fn CloneContents(&self, can_gc: CanGc) -> Fallible<DomRoot<DocumentFragment>> {
fn CloneContents(&self, cx: &mut JSContext) -> Fallible<DomRoot<DocumentFragment>> {
// Step 3.
let start_node = self.start_container();
let start_offset = self.start_offset();
@@ -604,7 +605,7 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
let end_offset = self.end_offset();
// Step 1.
let fragment = DocumentFragment::new(&start_node.owner_doc(), can_gc);
let fragment = DocumentFragment::new(&start_node.owner_doc(), CanGc::from_cx(cx));
// Step 2.
if self.start() == self.end() {
@@ -617,9 +618,12 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
let data = cdata
.SubstringData(start_offset, end_offset - start_offset)
.unwrap();
let clone = cdata.clone_with_data(data, &start_node.owner_doc(), can_gc);
let clone =
cdata.clone_with_data(data, &start_node.owner_doc(), CanGc::from_cx(cx));
// Step 4.3.
fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
fragment
.upcast::<Node>()
.AppendChild(&clone, CanGc::from_cx(cx))?;
// Step 4.4
return Ok(fragment);
}
@@ -640,14 +644,19 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
let data = cdata
.SubstringData(start_offset, start_node.len() - start_offset)
.unwrap();
let clone = cdata.clone_with_data(data, &start_node.owner_doc(), can_gc);
let clone =
cdata.clone_with_data(data, &start_node.owner_doc(), CanGc::from_cx(cx));
// Step 13.3.
fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
fragment
.upcast::<Node>()
.AppendChild(&clone, CanGc::from_cx(cx))?;
} else {
// Step 14.1.
let clone = child.CloneNode(/* deep */ false, can_gc)?;
let clone = child.CloneNode(cx, /* deep */ false)?;
// Step 14.2.
fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
fragment
.upcast::<Node>()
.AppendChild(&clone, CanGc::from_cx(cx))?;
// Step 14.3.
let subrange = Range::new(
&clone.owner_doc(),
@@ -655,21 +664,23 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
start_offset,
&child,
child.len(),
can_gc,
CanGc::from_cx(cx),
);
// Step 14.4.
let subfragment = subrange.CloneContents(can_gc)?;
let subfragment = subrange.CloneContents(cx)?;
// Step 14.5.
clone.AppendChild(subfragment.upcast(), can_gc)?;
clone.AppendChild(subfragment.upcast(), CanGc::from_cx(cx))?;
}
}
// Step 15.
for child in contained_children {
// Step 15.1.
let clone = child.CloneNode(/* deep */ true, can_gc)?;
let clone = child.CloneNode(cx, /* deep */ true)?;
// Step 15.2.
fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
fragment
.upcast::<Node>()
.AppendChild(&clone, CanGc::from_cx(cx))?;
}
if let Some(child) = last_partially_contained_child {
@@ -678,21 +689,32 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
assert!(child == end_node);
// Steps 16.1-2.
let data = cdata.SubstringData(0, end_offset).unwrap();
let clone = cdata.clone_with_data(data, &start_node.owner_doc(), can_gc);
let clone =
cdata.clone_with_data(data, &start_node.owner_doc(), CanGc::from_cx(cx));
// Step 16.3.
fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
fragment
.upcast::<Node>()
.AppendChild(&clone, CanGc::from_cx(cx))?;
} else {
// Step 17.1.
let clone = child.CloneNode(/* deep */ false, can_gc)?;
let clone = child.CloneNode(cx, /* deep */ false)?;
// Step 17.2.
fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
fragment
.upcast::<Node>()
.AppendChild(&clone, CanGc::from_cx(cx))?;
// Step 17.3.
let subrange =
Range::new(&clone.owner_doc(), &child, 0, &end_node, end_offset, can_gc);
let subrange = Range::new(
&clone.owner_doc(),
&child,
0,
&end_node,
end_offset,
CanGc::from_cx(cx),
);
// Step 17.4.
let subfragment = subrange.CloneContents(can_gc)?;
let subfragment = subrange.CloneContents(cx)?;
// Step 17.5.
clone.AppendChild(subfragment.upcast(), can_gc)?;
clone.AppendChild(subfragment.upcast(), CanGc::from_cx(cx))?;
}
}
@@ -702,7 +724,7 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
/// <https://dom.spec.whatwg.org/#dom-range-extractcontents>
/// <https://dom.spec.whatwg.org/#concept-range-extract>
fn ExtractContents(&self, can_gc: CanGc) -> Fallible<DomRoot<DocumentFragment>> {
fn ExtractContents(&self, cx: &mut JSContext) -> Fallible<DomRoot<DocumentFragment>> {
// Step 3.
let start_node = self.start_container();
let start_offset = self.start_offset();
@@ -710,7 +732,7 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
let end_offset = self.end_offset();
// Step 1.
let fragment = DocumentFragment::new(&start_node.owner_doc(), can_gc);
let fragment = DocumentFragment::new(&start_node.owner_doc(), CanGc::from_cx(cx));
// Step 2.
if self.collapsed() {
@@ -720,7 +742,7 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
if end_node == start_node {
if let Some(end_data) = end_node.downcast::<CharacterData>() {
// Step 4.1.
let clone = end_node.CloneNode(/* deep */ true, can_gc)?;
let clone = end_node.CloneNode(cx, /* deep */ true)?;
// Step 4.2.
let text = end_data.SubstringData(start_offset, end_offset - start_offset);
clone
@@ -728,7 +750,9 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
.unwrap()
.SetData(text.unwrap());
// Step 4.3.
fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
fragment
.upcast::<Node>()
.AppendChild(&clone, CanGc::from_cx(cx))?;
// Step 4.4.
end_data.ReplaceData(start_offset, end_offset - start_offset, DOMString::new())?;
// Step 4.5.
@@ -764,7 +788,7 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
if let Some(start_data) = child.downcast::<CharacterData>() {
assert!(child == start_node);
// Step 15.1.
let clone = start_node.CloneNode(/* deep */ true, can_gc)?;
let clone = start_node.CloneNode(cx, /* deep */ true)?;
// Step 15.2.
let text = start_data.SubstringData(start_offset, start_node.len() - start_offset);
clone
@@ -772,7 +796,9 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
.unwrap()
.SetData(text.unwrap());
// Step 15.3.
fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
fragment
.upcast::<Node>()
.AppendChild(&clone, CanGc::from_cx(cx))?;
// Step 15.4.
start_data.ReplaceData(
start_offset,
@@ -781,9 +807,11 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
)?;
} else {
// Step 16.1.
let clone = child.CloneNode(/* deep */ false, can_gc)?;
let clone = child.CloneNode(cx, /* deep */ false)?;
// Step 16.2.
fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
fragment
.upcast::<Node>()
.AppendChild(&clone, CanGc::from_cx(cx))?;
// Step 16.3.
let subrange = Range::new(
&clone.owner_doc(),
@@ -791,25 +819,27 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
start_offset,
&child,
child.len(),
can_gc,
CanGc::from_cx(cx),
);
// Step 16.4.
let subfragment = subrange.ExtractContents(can_gc)?;
let subfragment = subrange.ExtractContents(cx)?;
// Step 16.5.
clone.AppendChild(subfragment.upcast(), can_gc)?;
clone.AppendChild(subfragment.upcast(), CanGc::from_cx(cx))?;
}
}
// Step 17.
for child in contained_children {
fragment.upcast::<Node>().AppendChild(&child, can_gc)?;
fragment
.upcast::<Node>()
.AppendChild(&child, CanGc::from_cx(cx))?;
}
if let Some(child) = last_partially_contained_child {
if let Some(end_data) = child.downcast::<CharacterData>() {
assert!(child == end_node);
// Step 18.1.
let clone = end_node.CloneNode(/* deep */ true, can_gc)?;
let clone = end_node.CloneNode(cx, /* deep */ true)?;
// Step 18.2.
let text = end_data.SubstringData(0, end_offset);
clone
@@ -817,21 +847,31 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
.unwrap()
.SetData(text.unwrap());
// Step 18.3.
fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
fragment
.upcast::<Node>()
.AppendChild(&clone, CanGc::from_cx(cx))?;
// Step 18.4.
end_data.ReplaceData(0, end_offset, DOMString::new())?;
} else {
// Step 19.1.
let clone = child.CloneNode(/* deep */ false, can_gc)?;
let clone = child.CloneNode(cx, /* deep */ false)?;
// Step 19.2.
fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
fragment
.upcast::<Node>()
.AppendChild(&clone, CanGc::from_cx(cx))?;
// Step 19.3.
let subrange =
Range::new(&clone.owner_doc(), &child, 0, &end_node, end_offset, can_gc);
let subrange = Range::new(
&clone.owner_doc(),
&child,
0,
&end_node,
end_offset,
CanGc::from_cx(cx),
);
// Step 19.4.
let subfragment = subrange.ExtractContents(can_gc)?;
let subfragment = subrange.ExtractContents(cx)?;
// Step 19.5.
clone.AppendChild(subfragment.upcast(), can_gc)?;
clone.AppendChild(subfragment.upcast(), CanGc::from_cx(cx))?;
}
}
@@ -1018,7 +1058,7 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
}
/// <https://dom.spec.whatwg.org/#dom-range-surroundcontents>
fn SurroundContents(&self, new_parent: &Node, can_gc: CanGc) -> ErrorResult {
fn SurroundContents(&self, cx: &mut JSContext, new_parent: &Node) -> ErrorResult {
// Step 1.
let start = self.start_container();
let end = self.end_container();
@@ -1043,16 +1083,16 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
}
// Step 3.
let fragment = self.ExtractContents(can_gc)?;
let fragment = self.ExtractContents(cx)?;
// Step 4.
Node::replace_all(None, new_parent, can_gc);
Node::replace_all(None, new_parent, CanGc::from_cx(cx));
// Step 5.
self.InsertNode(new_parent, can_gc)?;
self.InsertNode(new_parent, CanGc::from_cx(cx))?;
// Step 6.
new_parent.AppendChild(fragment.upcast(), can_gc)?;
new_parent.AppendChild(fragment.upcast(), CanGc::from_cx(cx))?;
// Step 7.
self.SelectNode(new_parent)
@@ -1113,7 +1153,7 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
/// <https://html.spec.whatwg.org/multipage/#dom-range-createcontextualfragment>
fn CreateContextualFragment(
&self,
cx: &mut js::context::JSContext,
cx: &mut JSContext,
fragment: TrustedHTMLOrString,
) -> Fallible<DomRoot<DocumentFragment>> {
// Step 2. Let node be this's start node.
@@ -1145,8 +1185,7 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
};
// Step 6. If element is null or all of the following are true:
let element =
Element::fragment_parsing_context(&owner_doc, element.as_deref(), CanGc::from_cx(cx));
let element = Element::fragment_parsing_context(cx, &owner_doc, element.as_deref());
// Step 7. Let fragment node be the result of invoking the fragment parsing algorithm steps with element and compliantString.
let fragment_node = element.parse_fragment(fragment, cx)?;

View File

@@ -1825,7 +1825,12 @@ impl TreeSink for Sink {
attach_declarative_shadow_inner(host, template, attributes)
}
#[expect(unsafe_code)]
fn maybe_clone_an_option_into_selectedcontent(&self, option: &Self::Handle) {
// TODO: https://github.com/servo/servo/issues/42839
let mut cx = unsafe { temp_cx() };
let cx = &mut cx;
let Some(option) = option.downcast::<HTMLOptionElement>() else {
if cfg!(debug_assertions) {
unreachable!();
@@ -1836,7 +1841,7 @@ impl TreeSink for Sink {
return;
};
option.maybe_clone_an_option_into_selectedcontent(CanGc::note())
option.maybe_clone_an_option_into_selectedcontent(cx)
}
}

View File

@@ -6,6 +6,7 @@ use base64::Engine as _;
use cssparser::{Parser, ParserInput};
use dom_struct::dom_struct;
use html5ever::{LocalName, Prefix, local_name, ns};
use js::context::JSContext;
use js::rust::HandleObject;
use layout_api::SVGElementData;
use servo_url::ServoUrl;
@@ -74,15 +75,18 @@ impl SVGSVGElement {
)
}
#[expect(unsafe_code)]
pub(crate) fn serialize_and_cache_subtree(&self) {
let can_gc = CanGc::note();
let cloned_nodes = self.process_use_elements(can_gc);
// TODO: https://github.com/servo/servo/issues/43142
let mut cx = unsafe { script_bindings::script_runtime::temp_cx() };
let cx = &mut cx;
let cloned_nodes = self.process_use_elements(cx);
let serialize_result = self
.upcast::<Node>()
.xml_serialize(TraversalScope::IncludeNode);
self.cleanup_cloned_nodes(&cloned_nodes, can_gc);
self.cleanup_cloned_nodes(&cloned_nodes, CanGc::from_cx(cx));
let Ok(xml_source) = serialize_result else {
*self.cached_serialized_data_url.borrow_mut() = Some(Err(()));
@@ -98,14 +102,14 @@ impl SVGSVGElement {
};
}
fn process_use_elements(&self, can_gc: CanGc) -> Vec<DomRoot<Node>> {
fn process_use_elements(&self, cx: &mut JSContext) -> Vec<DomRoot<Node>> {
let mut cloned_nodes = Vec::new();
let root_node = self.upcast::<Node>();
for node in root_node.traverse_preorder(ShadowIncluding::No) {
if let Some(element) = node.downcast::<Element>() {
if element.local_name() == &local_name!("use") {
if let Some(cloned) = self.process_single_use_element(element, can_gc) {
if let Some(cloned) = self.process_single_use_element(cx, element) {
cloned_nodes.push(cloned);
}
}
@@ -117,8 +121,8 @@ impl SVGSVGElement {
fn process_single_use_element(
&self,
cx: &mut JSContext,
use_element: &Element,
can_gc: CanGc,
) -> Option<DomRoot<Node>> {
let href = use_element.get_string_attribute(&local_name!("href"));
let href_view = href.str();
@@ -134,14 +138,14 @@ impl SVGSVGElement {
return None;
}
let cloned_node = Node::clone(
cx,
referenced_node,
None,
CloneChildrenFlag::CloneChildren,
None,
can_gc,
);
let root_node = self.upcast::<Node>();
let _ = root_node.AppendChild(&cloned_node, can_gc);
let _ = root_node.AppendChild(&cloned_node, CanGc::from_cx(cx));
Some(cloned_node)
}

View File

@@ -177,13 +177,13 @@ pub(crate) trait VirtualMethods {
/// <https://dom.spec.whatwg.org/#concept-node-clone-ext>
fn cloning_steps(
&self,
cx: &mut JSContext,
copy: &Node,
maybe_doc: Option<&Document>,
clone_children: CloneChildrenFlag,
can_gc: CanGc,
) {
if let Some(s) = self.super_type() {
s.cloning_steps(copy, maybe_doc, clone_children, can_gc);
s.cloning_steps(cx, copy, maybe_doc, clone_children);
}
}

View File

@@ -193,12 +193,13 @@ DOMInterfaces = {
'Document': {
'additionalTraits': ["crate::interfaces::DocumentHelpers"],
'canGc': ['ImportNode', 'CreateEvent', 'CreateRange', 'CreateComment', 'CreateAttribute', 'CreateAttributeNS', 'CreateDocumentFragment', 'CreateTextNode', 'CreateCDATASection', 'CreateProcessingInstruction', 'Prepend', 'Append', 'ReplaceChildren', 'SetBgColor', 'SetFgColor', 'Fonts', 'ExitFullscreen', 'CreateExpression', 'CreateNSResolver', 'Evaluate', 'StyleSheets', 'Implementation', 'GetElementsByTagName', 'GetElementsByTagNameNS', 'GetElementsByClassName', 'AdoptNode', 'CreateNodeIterator', 'SetBody', 'GetElementsByName', 'Images', 'Embeds', 'Plugins', 'Links', 'Forms', 'Scripts', 'Anchors', 'Applets', 'Children', 'GetSelection', 'NamedGetter', 'AdoptedStyleSheets', 'SetAdoptedStyleSheets', 'MoveBefore'],
'canGc': ['CreateEvent', 'CreateRange', 'CreateComment', 'CreateAttribute', 'CreateAttributeNS', 'CreateDocumentFragment', 'CreateTextNode', 'CreateCDATASection', 'CreateProcessingInstruction', 'Prepend', 'Append', 'ReplaceChildren', 'SetBgColor', 'SetFgColor', 'Fonts', 'ExitFullscreen', 'CreateExpression', 'CreateNSResolver', 'Evaluate', 'StyleSheets', 'Implementation', 'GetElementsByTagName', 'GetElementsByTagNameNS', 'GetElementsByClassName', 'AdoptNode', 'CreateNodeIterator', 'SetBody', 'GetElementsByName', 'Images', 'Embeds', 'Plugins', 'Links', 'Forms', 'Scripts', 'Anchors', 'Applets', 'Children', 'GetSelection', 'NamedGetter', 'AdoptedStyleSheets', 'SetAdoptedStyleSheets', 'MoveBefore'],
'cx': [
'Close',
'CreateElement',
'CreateElementNS',
'ExecCommand',
'ImportNode',
'Open',
'Open_',
'ParseHTMLUnsafe',
@@ -657,7 +658,8 @@ DOMInterfaces = {
},
'Node': {
'canGc': ['AppendChild', 'ChildNodes', 'CloneNode', 'InsertBefore', 'Normalize', 'SetNodeValue', 'SetTextContent', 'RemoveChild', 'ReplaceChild'],
'canGc': ['AppendChild', 'ChildNodes', 'InsertBefore', 'Normalize', 'SetNodeValue', 'SetTextContent', 'RemoveChild', 'ReplaceChild'],
'cx': ['CloneNode']
},
'NodeIterator': {
@@ -705,9 +707,9 @@ DOMInterfaces = {
},
'Range': {
'canGc': ['CloneContents', 'CloneRange', 'ExtractContents', 'SurroundContents', 'InsertNode', 'GetClientRects', 'GetBoundingClientRect'],
'canGc': ['CloneRange', 'InsertNode', 'GetClientRects', 'GetBoundingClientRect'],
'weakReferenceable': True,
'cx': ['CreateContextualFragment'],
'cx': ['CloneContents', 'CreateContextualFragment', 'ExtractContents', 'SurroundContents'],
},
'Request': {