diff options
Diffstat (limited to 'components/script')
41 files changed, 704 insertions, 393 deletions
diff --git a/components/script/document_loader.rs b/components/script/document_loader.rs index 2d369697303..0b2a0ab8139 100644 --- a/components/script/document_loader.rs +++ b/components/script/document_loader.rs @@ -14,6 +14,7 @@ use servo_url::ServoUrl; use crate::dom::bindings::root::Dom; use crate::dom::document::Document; use crate::fetch::FetchCanceller; +use crate::script_runtime::CanGc; #[derive(Clone, Debug, JSTraceable, MallocSizeOf, PartialEq)] pub enum LoadType { @@ -48,9 +49,9 @@ impl LoadBlocker { } /// Remove this load from the associated document's list of blocking loads. - pub fn terminate(blocker: &mut Option<LoadBlocker>) { + pub fn terminate(blocker: &mut Option<LoadBlocker>, can_gc: CanGc) { if let Some(this) = blocker.as_mut() { - this.doc.finish_load(this.load.take().unwrap()); + this.doc.finish_load(this.load.take().unwrap(), can_gc); } *blocker = None; } @@ -59,7 +60,7 @@ impl LoadBlocker { impl Drop for LoadBlocker { fn drop(&mut self) { if let Some(load) = self.load.take() { - self.doc.finish_load(load); + self.doc.finish_load(load, CanGc::note()); } } } diff --git a/components/script/dom/abstractworkerglobalscope.rs b/components/script/dom/abstractworkerglobalscope.rs index b5af70a3647..1f2fe94ffcc 100644 --- a/components/script/dom/abstractworkerglobalscope.rs +++ b/components/script/dom/abstractworkerglobalscope.rs @@ -13,7 +13,7 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::worker::TrustedWorkerAddress; use crate::dom::workerglobalscope::WorkerGlobalScope; use crate::realms::enter_realm; -use crate::script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort}; +use crate::script_runtime::{CanGc, CommonScriptMsg, ScriptChan, ScriptPort}; use crate::task_queue::{QueuedTaskConversion, TaskQueue}; /// A ScriptChan that can be cloned freely and will silently send a TrustedWorkerAddress with @@ -101,6 +101,7 @@ pub trait WorkerEventLoopMethods { pub fn run_worker_event_loop<T, WorkerMsg, Event>( worker_scope: &T, worker: Option<&TrustedWorkerAddress>, + _can_gc: CanGc, ) where WorkerMsg: QueuedTaskConversion + Send, T: WorkerEventLoopMethods<WorkerMsg = WorkerMsg, Event = Event> @@ -155,7 +156,7 @@ pub fn run_worker_event_loop<T, WorkerMsg, Event>( }; worker_scope .upcast::<GlobalScope>() - .perform_a_microtask_checkpoint(); + .perform_a_microtask_checkpoint(CanGc::note()); } worker_scope .upcast::<GlobalScope>() diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index 94137dcc6a7..50d9bb6e7c7 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -40,6 +40,7 @@ DOMInterfaces = { 'Range': { 'weakReferenceable': True, + 'canGc': ['CreateContextualFragment', 'ExtractContents', 'CloneContents', 'CloneRange', 'SurroundContents'], }, 'EventSource': { @@ -70,6 +71,7 @@ DOMInterfaces = { 'Window': { 'inRealms': ['Fetch', 'GetOpener'], + 'canGc': ['Stop'], }, 'WorkerGlobalScope': { @@ -90,6 +92,7 @@ DOMInterfaces = { 'HTMLMediaElement': { 'inRealms': ['Play'], + 'canGc': ['Play', 'Pause', 'Load', 'SetSrcObject'], }, 'BluetoothRemoteGATTDescriptor': { @@ -180,6 +183,39 @@ DOMInterfaces = { 'GamepadHapticActuator': { 'inRealms': ['PlayEffect', 'Reset'] -} +}, + +'DOMParser': { + 'canGc': ['ParseFromString'], +}, + +'XMLHttpRequest': { + 'canGc': ['Response', 'GetResponseXML'], +}, + +'DOMImplementation': { + 'canGc': ['CreateHTMLDocument', 'CreateDocument'], +}, + +'HTMLTemplateElement': { + 'canGc': ['Content'], +}, + +'Element': { + 'canGc': ['SetInnerHTML', 'SetOuterHTML', 'InsertAdjacentHTML'], +}, + +'Selection': { + 'canGc': ['Extend', 'SetBaseAndExtent', 'SelectAllChildren', 'Collapse', 'SetPosition', + 'CollapseToStart', 'CollapseToEnd'], +}, + +'Document': { + 'canGc': ['Write', 'Writeln', 'Close', 'SetTitle', 'CreateElementNS', 'CreateElement', 'ImportNode'], +}, + +'Node': { + 'canGc': ['CloneNode'], +}, } diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 46d603955ab..cf8e70441c5 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -3700,6 +3700,8 @@ class CGCallGenerator(CGThing): args.prepend(CGGeneric("cx")) if nativeMethodName in descriptor.inRealmMethods: args.append(CGGeneric("InRealm::already(&AlreadyInRealm::assert_for_cx(cx))")) + if nativeMethodName in descriptor.canGcMethods: + args.append(CGGeneric("CanGc::note()")) # Build up our actual call self.cgRoot = CGList([], "\n") @@ -3723,7 +3725,7 @@ class CGCallGenerator(CGThing): ])) if hasCEReactions: - self.cgRoot.append(CGGeneric("pop_current_element_queue();\n")) + self.cgRoot.append(CGGeneric("pop_current_element_queue(CanGc::note());\n")) if isFallible: if static: @@ -6263,7 +6265,7 @@ class CGInterfaceTrait(CGThing): def __init__(self, descriptor): CGThing.__init__(self) - def attribute_arguments(needCx, argument=None, inRealm=False): + def attribute_arguments(needCx, argument=None, inRealm=False, canGc=False): if needCx: yield "cx", "SafeJSContext" @@ -6273,6 +6275,9 @@ class CGInterfaceTrait(CGThing): if inRealm: yield "_comp", "InRealm" + if canGc: + yield "_can_gc", "CanGc" + def members(): for m in descriptor.interface.members: if (m.isMethod() and not m.isStatic() @@ -6283,7 +6288,8 @@ class CGInterfaceTrait(CGThing): infallible = 'infallible' in descriptor.getExtendedAttributes(m) for idx, (rettype, arguments) in enumerate(m.signatures()): arguments = method_arguments(descriptor, rettype, arguments, - inRealm=name in descriptor.inRealmMethods) + inRealm=name in descriptor.inRealmMethods, + canGc=name in descriptor.canGcMethods) rettype = return_type(descriptor, rettype, infallible) yield f"{name}{'_' * idx}", arguments, rettype elif m.isAttr() and not m.isStatic(): @@ -6292,7 +6298,8 @@ class CGInterfaceTrait(CGThing): yield (name, attribute_arguments( typeNeedsCx(m.type, True), - inRealm=name in descriptor.inRealmMethods + inRealm=name in descriptor.inRealmMethods, + canGc=name in descriptor.canGcMethods ), return_type(descriptor, m.type, infallible)) @@ -6307,7 +6314,8 @@ class CGInterfaceTrait(CGThing): attribute_arguments( typeNeedsCx(m.type, False), m.type, - inRealm=name in descriptor.inRealmMethods + inRealm=name in descriptor.inRealmMethods, + canGc=name in descriptor.canGcMethods ), rettype) @@ -6324,7 +6332,8 @@ class CGInterfaceTrait(CGThing): if not rettype.nullable(): rettype = IDLNullableType(rettype.location, rettype) arguments = method_arguments(descriptor, rettype, arguments, - inRealm=name in descriptor.inRealmMethods) + inRealm=name in descriptor.inRealmMethods, + canGc=name in descriptor.canGcMethods) # If this interface 'supports named properties', then we # should be able to access 'supported property names' @@ -6335,7 +6344,8 @@ class CGInterfaceTrait(CGThing): yield "SupportedPropertyNames", [], "Vec<DOMString>" else: arguments = method_arguments(descriptor, rettype, arguments, - inRealm=name in descriptor.inRealmMethods) + inRealm=name in descriptor.inRealmMethods, + canGc=name in descriptor.canGcMethods) rettype = return_type(descriptor, rettype, infallible) yield name, arguments, rettype @@ -7123,7 +7133,8 @@ def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, var return declType.define() -def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, trailing=None, inRealm=False): +def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, trailing=None, + inRealm=False, canGc=False): if needCx(returnType, arguments, passJSBits): yield "cx", "SafeJSContext" @@ -7138,6 +7149,9 @@ def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, if inRealm: yield "_comp", "InRealm" + if canGc: + yield "_can_gc", "CanGc" + def return_type(descriptorProvider, rettype, infallible): result = getRetvalDeclarationForType(rettype, descriptorProvider) diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index 81ebe68d8bb..2f067c39256 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -232,6 +232,7 @@ class Descriptor(DescriptorProvider): self.register = desc.get('register', True) self.path = desc.get('path', pathDefault) self.inRealmMethods = [name for name in desc.get('inRealms', [])] + self.canGcMethods = [name for name in desc.get('canGc', [])] self.bindingPath = f"{getModuleFromObject(self.interface)}::{ifaceName}_Binding" self.outerObjectHook = desc.get('outerObjectHook', 'None') self.proxy = False diff --git a/components/script/dom/bindings/htmlconstructor.rs b/components/script/dom/bindings/htmlconstructor.rs index 111f78751d7..56aedc04840 100644 --- a/components/script/dom/bindings/htmlconstructor.rs +++ b/components/script/dom/bindings/htmlconstructor.rs @@ -51,7 +51,7 @@ use crate::dom::element::{Element, ElementCreator}; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlelement::HTMLElement; use crate::dom::window::Window; -use crate::script_runtime::{JSContext, JSContext as SafeJSContext}; +use crate::script_runtime::{CanGc, JSContext, JSContext as SafeJSContext}; use crate::script_thread::ScriptThread; // https://html.spec.whatwg.org/multipage/#htmlconstructor @@ -369,8 +369,8 @@ pub fn get_constructor_object_from_local_name( } } -pub fn pop_current_element_queue() { - ScriptThread::pop_current_element_queue(); +pub fn pop_current_element_queue(can_gc: CanGc) { + ScriptThread::pop_current_element_queue(can_gc); } pub fn push_new_element_queue() { diff --git a/components/script/dom/bindings/settings_stack.rs b/components/script/dom/bindings/settings_stack.rs index 113c9c3d404..0e913eb3de6 100644 --- a/components/script/dom/bindings/settings_stack.rs +++ b/components/script/dom/bindings/settings_stack.rs @@ -11,6 +11,7 @@ use js::rust::Runtime; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::trace::JSTraceable; use crate::dom::globalscope::GlobalScope; +use crate::script_runtime::CanGc; thread_local!(static STACK: RefCell<Vec<StackEntry>> = const { RefCell::new(Vec::new()) }); @@ -76,7 +77,7 @@ impl Drop for AutoEntryScript { // Step 5 if !thread::panicking() && incumbent_global().is_none() { - self.global.perform_a_microtask_checkpoint(); + self.global.perform_a_microtask_checkpoint(CanGc::note()); } } } diff --git a/components/script/dom/create.rs b/components/script/dom/create.rs index 771f19189f2..e1b6bb5dd3d 100644 --- a/components/script/dom/create.rs +++ b/components/script/dom/create.rs @@ -86,6 +86,7 @@ use crate::dom::htmlvideoelement::HTMLVideoElement; use crate::dom::svgelement::SVGElement; use crate::dom::svgsvgelement::SVGSVGElement; use crate::realms::{enter_realm, InRealm}; +use crate::script_runtime::CanGc; use crate::script_thread::ScriptThread; fn create_svg_element( @@ -127,6 +128,7 @@ fn create_html_element( creator: ElementCreator, mode: CustomElementCreationMode, proto: Option<HandleObject>, + can_gc: CanGc, ) -> DomRoot<Element> { assert_eq!(name.ns, ns!(html)); @@ -150,7 +152,7 @@ fn create_html_element( CustomElementCreationMode::Synchronous => { let local_name = name.local.clone(); //TODO(jdm) Pass proto to create_element? - return match definition.create_element(document, prefix.clone()) { + return match definition.create_element(document, prefix.clone(), can_gc) { Ok(element) => { element.set_custom_element_definition(definition.clone()); element @@ -185,7 +187,9 @@ fn create_html_element( element.set_custom_element_state(CustomElementState::Undefined); match mode { // Step 5.3 - CustomElementCreationMode::Synchronous => upgrade_element(definition, &element), + CustomElementCreationMode::Synchronous => { + upgrade_element(definition, &element, can_gc) + }, // Step 5.4 CustomElementCreationMode::Asynchronous => { ScriptThread::enqueue_upgrade_reaction(&element, definition) @@ -395,10 +399,11 @@ pub fn create_element( creator: ElementCreator, mode: CustomElementCreationMode, proto: Option<HandleObject>, + can_gc: CanGc, ) -> DomRoot<Element> { let prefix = name.prefix.clone(); match name.ns { - ns!(html) => create_html_element(name, prefix, is, document, creator, mode, proto), + ns!(html) => create_html_element(name, prefix, is, document, creator, mode, proto, can_gc), ns!(svg) => create_svg_element(name, prefix, document, proto), _ => Element::new(name.local, name.ns, prefix, document, proto), } diff --git a/components/script/dom/customelementregistry.rs b/components/script/dom/customelementregistry.rs index d1dfa4754fe..a0dabd1300a 100644 --- a/components/script/dom/customelementregistry.rs +++ b/components/script/dom/customelementregistry.rs @@ -48,7 +48,7 @@ use crate::dom::promise::Promise; use crate::dom::window::Window; use crate::microtask::Microtask; use crate::realms::{enter_realm, InRealm}; -use crate::script_runtime::JSContext; +use crate::script_runtime::{CanGc, JSContext}; use crate::script_thread::ScriptThread; /// <https://dom.spec.whatwg.org/#concept-element-custom-element-state> @@ -718,6 +718,7 @@ impl CustomElementDefinition { &self, document: &Document, prefix: Option<Prefix>, + can_gc: CanGc, ) -> Fallible<DomRoot<Element>> { let window = document.window(); let cx = GlobalScope::get_cx(); @@ -738,7 +739,7 @@ impl CustomElementDefinition { if is_execution_stack_empty() { window .upcast::<GlobalScope>() - .perform_a_microtask_checkpoint(); + .perform_a_microtask_checkpoint(can_gc); } rooted!(in(*cx) let element_val = ObjectValue(element.get())); @@ -783,7 +784,7 @@ impl CustomElementDefinition { /// <https://html.spec.whatwg.org/multipage/#concept-upgrade-an-element> #[allow(unsafe_code)] -pub fn upgrade_element(definition: Rc<CustomElementDefinition>, element: &Element) { +pub fn upgrade_element(definition: Rc<CustomElementDefinition>, element: &Element, can_gc: CanGc) { // Step 1 let state = element.get_custom_element_state(); if state != CustomElementState::Undefined && state != CustomElementState::Uncustomized { @@ -824,7 +825,7 @@ pub fn upgrade_element(definition: Rc<CustomElementDefinition>, element: &Elemen .push(ConstructionStackEntry::Element(DomRoot::from_ref(element))); // Steps 7-8, successful case - let result = run_upgrade_constructor(&definition.constructor, element); + let result = run_upgrade_constructor(&definition.constructor, element, can_gc); // "regardless of whether the above steps threw an exception" step definition.construction_stack.borrow_mut().pop(); @@ -897,6 +898,7 @@ pub fn upgrade_element(definition: Rc<CustomElementDefinition>, element: &Elemen fn run_upgrade_constructor( constructor: &Rc<CustomElementConstructor>, element: &Element, + can_gc: CanGc, ) -> ErrorResult { let window = window_from_node(element); let cx = GlobalScope::get_cx(); @@ -929,7 +931,7 @@ fn run_upgrade_constructor( if is_execution_stack_empty() { window .upcast::<GlobalScope>() - .perform_a_microtask_checkpoint(); + .perform_a_microtask_checkpoint(can_gc); } // Step 8.3 @@ -982,11 +984,11 @@ pub enum CustomElementReaction { impl CustomElementReaction { /// <https://html.spec.whatwg.org/multipage/#invoke-custom-element-reactions> #[allow(unsafe_code)] - pub fn invoke(&self, element: &Element) { + pub fn invoke(&self, element: &Element, can_gc: CanGc) { // Step 2.1 match *self { CustomElementReaction::Upgrade(ref definition) => { - upgrade_element(definition.clone(), element) + upgrade_element(definition.clone(), element, can_gc) }, CustomElementReaction::Callback(ref callback, ref arguments) => { // We're rooted, so it's safe to hand out a handle to objects in Heap @@ -1039,12 +1041,12 @@ impl CustomElementReactionStack { self.stack.borrow_mut().push(ElementQueue::new()); } - pub fn pop_current_element_queue(&self) { + pub fn pop_current_element_queue(&self, can_gc: CanGc) { rooted_vec!(let mut stack); mem::swap(&mut *stack, &mut *self.stack.borrow_mut()); if let Some(current_queue) = stack.last() { - current_queue.invoke_reactions(); + current_queue.invoke_reactions(can_gc); } stack.pop(); @@ -1054,9 +1056,9 @@ impl CustomElementReactionStack { /// <https://html.spec.whatwg.org/multipage/#enqueue-an-element-on-the-appropriate-element-queue> /// Step 4 - pub fn invoke_backup_element_queue(&self) { + pub fn invoke_backup_element_queue(&self, can_gc: CanGc) { // Step 4.1 - self.backup_queue.invoke_reactions(); + self.backup_queue.invoke_reactions(can_gc); // Step 4.2 self.processing_backup_element_queue @@ -1237,10 +1239,10 @@ impl ElementQueue { } /// <https://html.spec.whatwg.org/multipage/#invoke-custom-element-reactions> - fn invoke_reactions(&self) { + fn invoke_reactions(&self, _can_gc: CanGc) { // Steps 1-2 while let Some(element) = self.next_element() { - element.invoke_reactions() + element.invoke_reactions(CanGc::note()) } self.queue.borrow_mut().clear(); } diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index 62c156b55de..ab833d3000b 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -55,8 +55,8 @@ use crate::fetch::load_whole_resource; use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; use crate::script_runtime::ScriptThreadEventCategory::WorkerEvent; use crate::script_runtime::{ - new_child_runtime, CommonScriptMsg, ContextForRequestInterrupt, JSContext as SafeJSContext, - Runtime, ScriptChan, ScriptPort, + new_child_runtime, CanGc, CommonScriptMsg, ContextForRequestInterrupt, + JSContext as SafeJSContext, Runtime, ScriptChan, ScriptPort, }; use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue}; use crate::task_source::networking::NetworkingTaskSource; @@ -333,6 +333,7 @@ impl DedicatedWorkerGlobalScope { gpu_id_hub: Arc<Identities>, control_receiver: Receiver<DedicatedWorkerControlMsg>, context_sender: Sender<ContextForRequestInterrupt>, + _can_gc: CanGc, ) -> JoinHandle<()> { let serialized_worker_url = worker_url.to_string(); let top_level_browsing_context_id = TopLevelBrowsingContextId::installed(); @@ -478,7 +479,7 @@ impl DedicatedWorkerGlobalScope { // until the event loop is destroyed, // which happens after the closing flag is set to true. while !scope.is_closing() { - run_worker_event_loop(&*global, Some(&worker)); + run_worker_event_loop(&*global, Some(&worker), CanGc::note()); } }, reporter_name, diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 800e4dc8824..b09d7ec19e9 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -2117,7 +2117,7 @@ impl Document { // https://html.spec.whatwg.org/multipage/#the-end // https://html.spec.whatwg.org/multipage/#delay-the-load-event - pub fn finish_load(&self, load: LoadType) { + pub fn finish_load(&self, load: LoadType, can_gc: CanGc) { // This does not delay the load event anymore. debug!("Document got finish_load: {:?}", load); self.loader.borrow_mut().finish_load(&load); @@ -2126,7 +2126,7 @@ impl Document { LoadType::Stylesheet(_) => { // A stylesheet finishing to load may unblock any pending // parsing-blocking script or deferred script. - self.process_pending_parsing_blocking_script(); + self.process_pending_parsing_blocking_script(can_gc); // Step 3. self.process_deferred_scripts(); @@ -2489,6 +2489,7 @@ impl Document { &self, element: &HTMLScriptElement, result: ScriptResult, + can_gc: CanGc, ) { { let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut(); @@ -2496,10 +2497,10 @@ impl Document { assert!(&*entry.element == element); entry.loaded(result); } - self.process_pending_parsing_blocking_script(); + self.process_pending_parsing_blocking_script(can_gc); } - fn process_pending_parsing_blocking_script(&self) { + fn process_pending_parsing_blocking_script(&self, can_gc: CanGc) { if self.script_blocking_stylesheets_count.get() > 0 { return; } @@ -2512,7 +2513,7 @@ impl Document { *self.pending_parsing_blocking_script.borrow_mut() = None; self.get_current_parser() .unwrap() - .resume_with_pending_parsing_blocking_script(&element, result); + .resume_with_pending_parsing_blocking_script(&element, result, can_gc); } } @@ -2629,7 +2630,7 @@ impl Document { } // https://html.spec.whatwg.org/multipage/#abort-a-document - pub fn abort(&self) { + pub fn abort(&self, can_gc: CanGc) { // We need to inhibit the loader before anything else. self.loader.borrow_mut().inhibit_events(); @@ -2637,7 +2638,7 @@ impl Document { for iframe in self.iter_iframes() { if let Some(document) = iframe.GetContentDocument() { // TODO: abort the active documents of every child browsing context. - document.abort(); + document.abort(CanGc::note()); // TODO: salvageable flag. } } @@ -2666,7 +2667,7 @@ impl Document { // Step 3. if let Some(parser) = self.get_current_parser() { self.active_parser_was_aborted.set(true); - parser.abort(); + parser.abort(can_gc); self.salvageable.set(false); } } @@ -3457,6 +3458,7 @@ impl Document { referrer_policy: Option<ReferrerPolicy>, status_code: Option<u16>, canceller: FetchCanceller, + can_gc: CanGc, ) -> DomRoot<Document> { Self::new_with_proto( window, @@ -3474,7 +3476,7 @@ impl Document { referrer_policy, status_code, canceller, - CanGc::note(), + can_gc, ) } @@ -3613,7 +3615,7 @@ impl Document { } /// <https://html.spec.whatwg.org/multipage/#appropriate-template-contents-owner-document> - pub fn appropriate_template_contents_owner_document(&self) -> DomRoot<Document> { + pub fn appropriate_template_contents_owner_document(&self, can_gc: CanGc) -> DomRoot<Document> { self.appropriate_template_contents_owner_document .or_init(|| { let doctype = if self.is_html_document { @@ -3637,6 +3639,7 @@ impl Document { None, None, Default::default(), + can_gc, ); new_doc .appropriate_template_contents_owner_document @@ -4351,6 +4354,7 @@ impl DocumentMethods for Document { &self, mut local_name: DOMString, options: StringOrElementCreationOptions, + can_gc: CanGc, ) -> Fallible<DomRoot<Element>> { if xml_name_type(&local_name) == Invalid { debug!("Not a valid element name"); @@ -4384,6 +4388,7 @@ impl DocumentMethods for Document { ElementCreator::ScriptCreated, CustomElementCreationMode::Synchronous, None, + can_gc, )) } @@ -4393,6 +4398,7 @@ impl DocumentMethods for Document { namespace: Option<DOMString>, qualified_name: DOMString, options: StringOrElementCreationOptions, + can_gc: CanGc, ) -> Fallible<DomRoot<Element>> { let (namespace, prefix, local_name) = validate_and_extract(namespace, &qualified_name)?; let name = QualName::new(prefix, namespace, local_name); @@ -4409,6 +4415,7 @@ impl DocumentMethods for Document { ElementCreator::ScriptCreated, CustomElementCreationMode::Synchronous, None, + can_gc, )) } @@ -4507,7 +4514,7 @@ impl DocumentMethods for Document { } // https://dom.spec.whatwg.org/#dom-document-importnode - fn ImportNode(&self, node: &Node, deep: bool) -> Fallible<DomRoot<Node>> { + fn ImportNode(&self, node: &Node, deep: bool, can_gc: CanGc) -> Fallible<DomRoot<Node>> { // Step 1. if node.is::<Document>() || node.is::<ShadowRoot>() { return Err(Error::NotSupported); @@ -4520,7 +4527,7 @@ impl DocumentMethods for Document { CloneChildrenFlag::DoNotCloneChildren }; - Ok(Node::clone(node, Some(self), clone_children)) + Ok(Node::clone(node, Some(self), clone_children, can_gc)) } // https://dom.spec.whatwg.org/#dom-document-adoptnode @@ -4656,7 +4663,7 @@ impl DocumentMethods for Document { } // https://html.spec.whatwg.org/multipage/#document.title - fn SetTitle(&self, title: DOMString) { + fn SetTitle(&self, title: DOMString, can_gc: CanGc) { let root = match self.GetDocumentElement() { Some(root) => root, None => return, @@ -4677,6 +4684,7 @@ impl DocumentMethods for Document { ElementCreator::ScriptCreated, CustomElementCreationMode::Synchronous, None, + can_gc, ); let parent = root.upcast::<Node>(); let child = elem.upcast::<Node>(); @@ -4702,6 +4710,7 @@ impl DocumentMethods for Document { ElementCreator::ScriptCreated, CustomElementCreationMode::Synchronous, None, + can_gc, ); head.upcast::<Node>().AppendChild(elem.upcast()).unwrap() }, @@ -5222,7 +5231,7 @@ impl DocumentMethods for Document { if self.has_browsing_context() { // spec says "stop document loading", // which is a process that does more than just abort - self.abort(); + self.abort(CanGc::note()); } // Step 9 @@ -5296,7 +5305,7 @@ impl DocumentMethods for Document { } // https://html.spec.whatwg.org/multipage/#dom-document-write - fn Write(&self, text: Vec<DOMString>) -> ErrorResult { + fn Write(&self, text: Vec<DOMString>, can_gc: CanGc) -> ErrorResult { if !self.is_html_document() { // Step 1. return Err(Error::InvalidState); @@ -5334,20 +5343,20 @@ impl DocumentMethods for Document { // TODO: handle reload override buffer. // Steps 6-8. - parser.write(text); + parser.write(text, can_gc); // Step 9. Ok(()) } // https://html.spec.whatwg.org/multipage/#dom-document-writeln - fn Writeln(&self, mut text: Vec<DOMString>) -> ErrorResult { + fn Writeln(&self, mut text: Vec<DOMString>, can_gc: CanGc) -> ErrorResult { text.push("\n".into()); - self.Write(text) + self.Write(text, can_gc) } // https://html.spec.whatwg.org/multipage/#dom-document-close - fn Close(&self) -> ErrorResult { + fn Close(&self, can_gc: CanGc) -> ErrorResult { if !self.is_html_document() { // Step 1. return Err(Error::InvalidState); @@ -5367,7 +5376,7 @@ impl DocumentMethods for Document { }; // Step 4-6. - parser.close(); + parser.close(can_gc); Ok(()) } diff --git a/components/script/dom/domimplementation.rs b/components/script/dom/domimplementation.rs index 00224056009..9266445ef17 100644 --- a/components/script/dom/domimplementation.rs +++ b/components/script/dom/domimplementation.rs @@ -28,6 +28,7 @@ use crate::dom::htmltitleelement::HTMLTitleElement; use crate::dom::node::Node; use crate::dom::text::Text; use crate::dom::xmldocument::XMLDocument; +use crate::script_runtime::CanGc; // https://dom.spec.whatwg.org/#domimplementation #[dom_struct] @@ -74,6 +75,7 @@ impl DOMImplementationMethods for DOMImplementation { maybe_namespace: Option<DOMString>, qname: DOMString, maybe_doctype: Option<&DocumentType>, + can_gc: CanGc, ) -> Fallible<DomRoot<XMLDocument>> { let win = self.document.window(); let loader = DocumentLoader::new(&self.document.loader()); @@ -108,7 +110,7 @@ impl DOMImplementationMethods for DOMImplementation { }); match doc .upcast::<Document>() - .CreateElementNS(maybe_namespace, qname, options) + .CreateElementNS(maybe_namespace, qname, options, can_gc) { Err(error) => return Err(error), Ok(elem) => Some(elem), @@ -137,7 +139,7 @@ impl DOMImplementationMethods for DOMImplementation { } // https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument - fn CreateHTMLDocument(&self, title: Option<DOMString>) -> DomRoot<Document> { + fn CreateHTMLDocument(&self, title: Option<DOMString>, can_gc: CanGc) -> DomRoot<Document> { let win = self.document.window(); let loader = DocumentLoader::new(&self.document.loader()); @@ -157,6 +159,7 @@ impl DOMImplementationMethods for DOMImplementation { None, None, Default::default(), + can_gc, ); { diff --git a/components/script/dom/domparser.rs b/components/script/dom/domparser.rs index 53325508360..0487761261f 100644 --- a/components/script/dom/domparser.rs +++ b/components/script/dom/domparser.rs @@ -62,6 +62,7 @@ impl DOMParserMethods for DOMParser { &self, s: DOMString, ty: DOMParserBinding::SupportedType, + can_gc: CanGc, ) -> Fallible<DomRoot<Document>> { let url = self.window.get_url(); let content_type = ty @@ -87,8 +88,9 @@ impl DOMParserMethods for DOMParser { None, None, Default::default(), + can_gc, ); - ServoParser::parse_html_document(&document, Some(s), url); + ServoParser::parse_html_document(&document, Some(s), url, CanGc::note()); document.set_ready_state(DocumentReadyState::Complete); Ok(document) }, @@ -108,8 +110,9 @@ impl DOMParserMethods for DOMParser { None, None, Default::default(), + can_gc, ); - ServoParser::parse_xml_document(&document, Some(s), url); + ServoParser::parse_xml_document(&document, Some(s), url, CanGc::note()); document.set_ready_state(DocumentReadyState::Complete); Ok(document) }, diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 73390e4133f..e6ea30db2c9 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -148,6 +148,7 @@ use crate::dom::validation::Validatable; use crate::dom::validitystate::ValidationFlags; use crate::dom::virtualmethods::{vtable_for, VirtualMethods}; use crate::dom::window::ReflowReason; +use crate::script_runtime::CanGc; use crate::script_thread::ScriptThread; use crate::stylesheet_loader::StylesheetOwner; use crate::task::TaskOnce; @@ -262,8 +263,9 @@ impl Element { creator: ElementCreator, mode: CustomElementCreationMode, proto: Option<HandleObject>, + can_gc: CanGc, ) -> DomRoot<Element> { - create_element(name, is, document, creator, mode, proto) + create_element(name, is, document, creator, mode, proto, can_gc) } pub fn new_inherited( @@ -397,7 +399,7 @@ impl Element { } } - pub fn invoke_reactions(&self) { + pub fn invoke_reactions(&self, _can_gc: CanGc) { loop { rooted_vec!(let mut reactions); match *self.rare_data_mut() { @@ -412,7 +414,7 @@ impl Element { } for reaction in reactions.iter() { - reaction.invoke(self); + reaction.invoke(self, CanGc::note()); } reactions.clear(); @@ -1872,15 +1874,19 @@ impl Element { } // https://w3c.github.io/DOM-Parsing/#parsing - pub fn parse_fragment(&self, markup: DOMString) -> Fallible<DomRoot<DocumentFragment>> { + pub fn parse_fragment( + &self, + markup: DOMString, + can_gc: CanGc, + ) -> Fallible<DomRoot<DocumentFragment>> { // Steps 1-2. // TODO(#11995): XML case. - let new_children = ServoParser::parse_html_fragment(self, markup); + let new_children = ServoParser::parse_html_fragment(self, markup, can_gc); // Step 3. // See https://github.com/w3c/DOM-Parsing/issues/61. let context_document = { if let Some(template) = self.downcast::<HTMLTemplateElement>() { - template.Content().upcast::<Node>().owner_doc() + template.Content(CanGc::note()).upcast::<Node>().owner_doc() } else { document_from_node(self) } @@ -2633,11 +2639,11 @@ impl ElementMethods for Element { } /// <https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML> - fn SetInnerHTML(&self, value: DOMString) -> ErrorResult { + fn SetInnerHTML(&self, value: DOMString, can_gc: CanGc) -> ErrorResult { // Step 2. // https://github.com/w3c/DOM-Parsing/issues/1 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() { - DomRoot::upcast(template.Content()) + DomRoot::upcast(template.Content(can_gc)) } else { DomRoot::from_ref(self.upcast()) }; @@ -2656,7 +2662,7 @@ impl ElementMethods for Element { } // Step 1. - let frag = self.parse_fragment(value)?; + let frag = self.parse_fragment(value, CanGc::note())?; Node::replace_all(Some(frag.upcast()), &target); Ok(()) @@ -2672,7 +2678,7 @@ impl ElementMethods for Element { } // https://w3c.github.io/DOM-Parsing/#dom-element-outerhtml - fn SetOuterHTML(&self, value: DOMString) -> ErrorResult { + fn SetOuterHTML(&self, value: DOMString, can_gc: CanGc) -> ErrorResult { let context_document = document_from_node(self); let context_node = self.upcast::<Node>(); // Step 1. @@ -2697,6 +2703,7 @@ impl ElementMethods for Element { ElementCreator::ScriptCreated, CustomElementCreationMode::Synchronous, None, + can_gc, ); DomRoot::upcast(body_elem) }, @@ -2704,7 +2711,7 @@ impl ElementMethods for Element { }; // Step 5. - let frag = parent.parse_fragment(value)?; + let frag = parent.parse_fragment(value, CanGc::note())?; // Step 6. context_parent.ReplaceChild(frag.upcast(), context_node)?; Ok(()) @@ -2862,7 +2869,12 @@ impl ElementMethods for Element { } // https://w3c.github.io/DOM-Parsing/#dom-element-insertadjacenthtml - fn InsertAdjacentHTML(&self, position: DOMString, text: DOMString) -> ErrorResult { + fn InsertAdjacentHTML( + &self, + position: DOMString, + text: DOMString, + can_gc: CanGc, + ) -> ErrorResult { // Step 1. let position = position.parse::<AdjacentPosition>()?; @@ -2886,7 +2898,7 @@ impl ElementMethods for Element { Element::fragment_parsing_context(&context.owner_doc(), context.downcast::<Element>()); // Step 3. - let fragment = context.parse_fragment(text)?; + let fragment = context.parse_fragment(text, can_gc)?; // Step 4. self.insert_adjacent(position, fragment.upcast()) diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index a14a750015c..680f9e652b2 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -120,7 +120,8 @@ use crate::microtask::{Microtask, MicrotaskQueue, UserMicrotask}; use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; use crate::script_module::{DynamicModuleList, ModuleScript, ModuleTree, ScriptFetchOptions}; use crate::script_runtime::{ - CommonScriptMsg, ContextForRequestInterrupt, JSContext as SafeJSContext, ScriptChan, ScriptPort, + CanGc, CommonScriptMsg, ContextForRequestInterrupt, JSContext as SafeJSContext, ScriptChan, + ScriptPort, }; use crate::script_thread::{MainThreadScriptChan, ScriptThread}; use crate::security_manager::CSPViolationReporter; @@ -2952,13 +2953,14 @@ impl GlobalScope { } /// Perform a microtask checkpoint. - pub fn perform_a_microtask_checkpoint(&self) { + pub fn perform_a_microtask_checkpoint(&self, can_gc: CanGc) { // Only perform the checkpoint if we're not shutting down. if self.can_continue_running() { self.microtask_queue.checkpoint( GlobalScope::get_cx(), |_| Some(DomRoot::from_ref(self)), vec![DomRoot::from_ref(self)], + can_gc, ); } } diff --git a/components/script/dom/htmlaudioelement.rs b/components/script/dom/htmlaudioelement.rs index 12ed22b0839..28161f13829 100644 --- a/components/script/dom/htmlaudioelement.rs +++ b/components/script/dom/htmlaudioelement.rs @@ -56,7 +56,7 @@ impl HTMLAudioElement { pub fn Audio( window: &Window, proto: Option<HandleObject>, - _can_gc: CanGc, + can_gc: CanGc, src: Option<DOMString>, ) -> Fallible<DomRoot<HTMLAudioElement>> { let element = Element::create( @@ -66,6 +66,7 @@ impl HTMLAudioElement { ElementCreator::ScriptCreated, CustomElementCreationMode::Synchronous, proto, + can_gc, ); let audio = DomRoot::downcast::<HTMLAudioElement>(element).unwrap(); diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 73edda35b33..17c0bb9896a 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -40,6 +40,7 @@ use crate::dom::node::{ }; use crate::dom::virtualmethods::VirtualMethods; use crate::dom::windowproxy::WindowProxy; +use crate::script_runtime::CanGc; use crate::script_thread::ScriptThread; #[derive(Clone, Copy, JSTraceable, MallocSizeOf)] @@ -114,8 +115,9 @@ impl HTMLIFrameElement { &self, load_data: LoadData, replace: HistoryEntryReplacement, + can_gc: CanGc, ) { - self.start_new_pipeline(load_data, PipelineType::Navigation, replace); + self.start_new_pipeline(load_data, PipelineType::Navigation, replace, can_gc); } fn start_new_pipeline( @@ -123,6 +125,7 @@ impl HTMLIFrameElement { mut load_data: LoadData, pipeline_type: PipelineType, replace: HistoryEntryReplacement, + can_gc: CanGc, ) { let sandboxed = if self.is_sandboxed() { IFrameSandboxed @@ -146,7 +149,7 @@ impl HTMLIFrameElement { let mut load_blocker = self.load_blocker.borrow_mut(); // Any oustanding load is finished from the point of view of the blocked // document; the new navigation will continue blocking it. - LoadBlocker::terminate(&mut load_blocker); + LoadBlocker::terminate(&mut load_blocker, can_gc); } if load_data.url.scheme() == "javascript" { @@ -241,7 +244,7 @@ impl HTMLIFrameElement { } /// <https://html.spec.whatwg.org/multipage/#process-the-iframe-attributes> - fn process_the_iframe_attributes(&self, mode: ProcessingMode) { + fn process_the_iframe_attributes(&self, mode: ProcessingMode, can_gc: CanGc) { // > 1. If `element`'s `srcdoc` attribute is specified, then: if self .upcast::<Element>() @@ -264,6 +267,7 @@ impl HTMLIFrameElement { self.navigate_or_reload_child_browsing_context( load_data, HistoryEntryReplacement::Disabled, + can_gc, ); return; } @@ -347,10 +351,10 @@ impl HTMLIFrameElement { } else { HistoryEntryReplacement::Disabled }; - self.navigate_or_reload_child_browsing_context(load_data, replace); + self.navigate_or_reload_child_browsing_context(load_data, replace, CanGc::note()); } - fn create_nested_browsing_context(&self) { + fn create_nested_browsing_context(&self, can_gc: CanGc) { // Synchronously create a new browsing context, which will present // `about:blank`. (This is not a navigation.) // @@ -389,6 +393,7 @@ impl HTMLIFrameElement { load_data, PipelineType::InitialAboutBlank, HistoryEntryReplacement::Disabled, + can_gc, ); } @@ -400,7 +405,12 @@ impl HTMLIFrameElement { self.browsing_context_id.set(None); } - pub fn update_pipeline_id(&self, new_pipeline_id: PipelineId, reason: UpdatePipelineIdReason) { + pub fn update_pipeline_id( + &self, + new_pipeline_id: PipelineId, + reason: UpdatePipelineIdReason, + can_gc: CanGc, + ) { if self.pending_pipeline_id.get() != Some(new_pipeline_id) && reason == UpdatePipelineIdReason::Navigation { @@ -413,7 +423,7 @@ impl HTMLIFrameElement { // The load blocker will be terminated for a navigation in iframe_load_event_steps. if reason == UpdatePipelineIdReason::Traversal { let mut blocker = self.load_blocker.borrow_mut(); - LoadBlocker::terminate(&mut blocker); + LoadBlocker::terminate(&mut blocker, can_gc); } self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); @@ -478,7 +488,7 @@ impl HTMLIFrameElement { } /// <https://html.spec.whatwg.org/multipage/#iframe-load-event-steps> steps 1-4 - pub fn iframe_load_event_steps(&self, loaded_pipeline: PipelineId) { + pub fn iframe_load_event_steps(&self, loaded_pipeline: PipelineId, can_gc: CanGc) { // TODO(#9592): assert that the load blocker is present at all times when we // can guarantee that it's created for the case of iframe.reload(). if Some(loaded_pipeline) != self.pending_pipeline_id.get() { @@ -495,7 +505,7 @@ impl HTMLIFrameElement { self.upcast::<EventTarget>().fire_event(atom!("load")); let mut blocker = self.load_blocker.borrow_mut(); - LoadBlocker::terminate(&mut blocker); + LoadBlocker::terminate(&mut blocker, can_gc); // TODO Step 5 - unset child document `mut iframe load` flag } @@ -667,7 +677,7 @@ impl VirtualMethods for HTMLIFrameElement { // trigger the processing of iframe attributes whenever "srcdoc" attribute is set, changed or removed if self.upcast::<Node>().is_connected_with_browsing_context() { debug!("iframe srcdoc modified while in browsing context."); - self.process_the_iframe_attributes(ProcessingMode::NotFirstTime); + self.process_the_iframe_attributes(ProcessingMode::NotFirstTime, CanGc::note()); } }, local_name!("src") => { @@ -681,7 +691,7 @@ impl VirtualMethods for HTMLIFrameElement { // the child browsing context to be created. if self.upcast::<Node>().is_connected_with_browsing_context() { debug!("iframe src set while in browsing context."); - self.process_the_iframe_attributes(ProcessingMode::NotFirstTime); + self.process_the_iframe_attributes(ProcessingMode::NotFirstTime, CanGc::note()); } }, _ => {}, @@ -718,8 +728,8 @@ impl VirtualMethods for HTMLIFrameElement { if this.upcast::<Node>().is_connected_with_browsing_context() { debug!("iframe bound to browsing context."); debug_assert!(tree_connected, "is_connected_with_bc, but not tree_connected"); - this.create_nested_browsing_context(); - this.process_the_iframe_attributes(ProcessingMode::FirstTime); + this.create_nested_browsing_context(CanGc::note()); + this.process_the_iframe_attributes(ProcessingMode::FirstTime, CanGc::note()); } })); } @@ -728,7 +738,7 @@ impl VirtualMethods for HTMLIFrameElement { self.super_type().unwrap().unbind_from_tree(context); let mut blocker = self.load_blocker.borrow_mut(); - LoadBlocker::terminate(&mut blocker); + LoadBlocker::terminate(&mut blocker, CanGc::note()); // https://html.spec.whatwg.org/multipage/#a-browsing-context-is-discarded let window = window_from_node(self); diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index 1a485ac8ddb..77b4f6344b1 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -332,7 +332,7 @@ pub(crate) fn image_fetch_request( #[allow(non_snake_case)] impl HTMLImageElement { /// Update the current image with a valid URL. - fn fetch_image(&self, img_url: &ServoUrl) { + fn fetch_image(&self, img_url: &ServoUrl, can_gc: CanGc) { let window = window_from_node(self); let image_cache = window.image_cache(); let sender = generate_cache_listener_for_element(self); @@ -351,17 +351,20 @@ impl HTMLImageElement { is_placeholder, }) => { if is_placeholder { - self.process_image_response(ImageResponse::PlaceholderLoaded(image, url)) + self.process_image_response( + ImageResponse::PlaceholderLoaded(image, url), + can_gc, + ) } else { - self.process_image_response(ImageResponse::Loaded(image, url)) + self.process_image_response(ImageResponse::Loaded(image, url), can_gc) } }, ImageCacheResult::Available(ImageOrMetadataAvailable::MetadataAvailable(m)) => { - self.process_image_response(ImageResponse::MetadataLoaded(m)) + self.process_image_response(ImageResponse::MetadataLoaded(m), can_gc) }, ImageCacheResult::Pending(_) => (), ImageCacheResult::ReadyForRequest(id) => self.fetch_request(img_url, id), - ImageCacheResult::LoadError => self.process_image_response(ImageResponse::None), + ImageCacheResult::LoadError => self.process_image_response(ImageResponse::None, can_gc), }; } @@ -418,7 +421,7 @@ impl HTMLImageElement { } // Steps common to when an image has been loaded. - fn handle_loaded_image(&self, image: Arc<Image>, url: ServoUrl) { + fn handle_loaded_image(&self, image: Arc<Image>, url: ServoUrl, can_gc: CanGc) { self.current_request.borrow_mut().metadata = Some(ImageMetadata { height: image.height, width: image.width, @@ -426,34 +429,34 @@ impl HTMLImageElement { self.current_request.borrow_mut().final_url = Some(url); self.current_request.borrow_mut().image = Some(image); self.current_request.borrow_mut().state = State::CompletelyAvailable; - LoadBlocker::terminate(&mut self.current_request.borrow_mut().blocker); + LoadBlocker::terminate(&mut self.current_request.borrow_mut().blocker, can_gc); // Mark the node dirty self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); self.resolve_image_decode_promises(); } /// Step 24 of <https://html.spec.whatwg.org/multipage/#update-the-image-data> - fn process_image_response(&self, image: ImageResponse) { + fn process_image_response(&self, image: ImageResponse, can_gc: CanGc) { // TODO: Handle multipart/x-mixed-replace let (trigger_image_load, trigger_image_error) = match (image, self.image_request.get()) { (ImageResponse::Loaded(image, url), ImageRequestPhase::Current) => { - self.handle_loaded_image(image, url); + self.handle_loaded_image(image, url, can_gc); (true, false) }, (ImageResponse::PlaceholderLoaded(image, url), ImageRequestPhase::Current) => { - self.handle_loaded_image(image, url); + self.handle_loaded_image(image, url, can_gc); (false, true) }, (ImageResponse::Loaded(image, url), ImageRequestPhase::Pending) => { - self.abort_request(State::Unavailable, ImageRequestPhase::Pending); + self.abort_request(State::Unavailable, ImageRequestPhase::Pending, can_gc); self.image_request.set(ImageRequestPhase::Current); - self.handle_loaded_image(image, url); + self.handle_loaded_image(image, url, CanGc::note()); (true, false) }, (ImageResponse::PlaceholderLoaded(image, url), ImageRequestPhase::Pending) => { - self.abort_request(State::Unavailable, ImageRequestPhase::Pending); + self.abort_request(State::Unavailable, ImageRequestPhase::Pending, can_gc); self.image_request.set(ImageRequestPhase::Current); - self.handle_loaded_image(image, url); + self.handle_loaded_image(image, url, CanGc::note()); (false, true) }, (ImageResponse::MetadataLoaded(meta), ImageRequestPhase::Current) => { @@ -466,12 +469,12 @@ impl HTMLImageElement { (false, false) }, (ImageResponse::None, ImageRequestPhase::Current) => { - self.abort_request(State::Broken, ImageRequestPhase::Current); + self.abort_request(State::Broken, ImageRequestPhase::Current, can_gc); (false, true) }, (ImageResponse::None, ImageRequestPhase::Pending) => { - self.abort_request(State::Broken, ImageRequestPhase::Current); - self.abort_request(State::Broken, ImageRequestPhase::Pending); + self.abort_request(State::Broken, ImageRequestPhase::Current, can_gc); + self.abort_request(State::Broken, ImageRequestPhase::Pending, CanGc::note()); self.image_request.set(ImageRequestPhase::Current); (false, true) }, @@ -501,6 +504,7 @@ impl HTMLImageElement { src: USVString, generation: u32, selected_pixel_density: f64, + can_gc: CanGc, ) { match image { ImageResponse::Loaded(image, url) | ImageResponse::PlaceholderLoaded(image, url) => { @@ -510,24 +514,29 @@ impl HTMLImageElement { }); self.pending_request.borrow_mut().final_url = Some(url); self.pending_request.borrow_mut().image = Some(image); - self.finish_reacting_to_environment_change(src, generation, selected_pixel_density); + self.finish_reacting_to_environment_change( + src, + generation, + selected_pixel_density, + can_gc, + ); }, ImageResponse::MetadataLoaded(meta) => { self.pending_request.borrow_mut().metadata = Some(meta); }, ImageResponse::None => { - self.abort_request(State::Unavailable, ImageRequestPhase::Pending); + self.abort_request(State::Unavailable, ImageRequestPhase::Pending, can_gc); }, }; } /// <https://html.spec.whatwg.org/multipage/#abort-the-image-request> - fn abort_request(&self, state: State, request: ImageRequestPhase) { + fn abort_request(&self, state: State, request: ImageRequestPhase, can_gc: CanGc) { let mut request = match request { ImageRequestPhase::Current => self.current_request.borrow_mut(), ImageRequestPhase::Pending => self.pending_request.borrow_mut(), }; - LoadBlocker::terminate(&mut request.blocker); + LoadBlocker::terminate(&mut request.blocker, can_gc); request.state = state; request.image = None; request.metadata = None; @@ -804,18 +813,25 @@ impl HTMLImageElement { request: &mut RefMut<ImageRequest>, url: &ServoUrl, src: &USVString, + can_gc: CanGc, ) { request.parsed_url = Some(url.clone()); request.source_url = Some(src.clone()); request.image = None; request.metadata = None; let document = document_from_node(self); - LoadBlocker::terminate(&mut request.blocker); + LoadBlocker::terminate(&mut request.blocker, can_gc); request.blocker = Some(LoadBlocker::new(&document, LoadType::Image(url.clone()))); } /// Step 13-17 of html.spec.whatwg.org/multipage/#update-the-image-data - fn prepare_image_request(&self, url: &ServoUrl, src: &USVString, selected_pixel_density: f64) { + fn prepare_image_request( + &self, + url: &ServoUrl, + src: &USVString, + selected_pixel_density: f64, + can_gc: CanGc, + ) { match self.image_request.get() { ImageRequestPhase::Pending => { if let Some(pending_url) = self.pending_request.borrow().parsed_url.clone() { @@ -836,33 +852,33 @@ impl HTMLImageElement { // Step 15 abort pending request pending_request.image = None; pending_request.parsed_url = None; - LoadBlocker::terminate(&mut pending_request.blocker); + LoadBlocker::terminate(&mut pending_request.blocker, can_gc); // TODO: queue a task to restart animation, if restart-animation is set return; } pending_request.current_pixel_density = Some(selected_pixel_density); self.image_request.set(ImageRequestPhase::Pending); - self.init_image_request(&mut pending_request, url, src); + self.init_image_request(&mut pending_request, url, src, can_gc); }, (_, State::Broken) | (_, State::Unavailable) => { // Step 17 current_request.current_pixel_density = Some(selected_pixel_density); - self.init_image_request(&mut current_request, url, src); + self.init_image_request(&mut current_request, url, src, can_gc); }, (_, _) => { // step 17 pending_request.current_pixel_density = Some(selected_pixel_density); self.image_request.set(ImageRequestPhase::Pending); - self.init_image_request(&mut pending_request, url, src); + self.init_image_request(&mut pending_request, url, src, can_gc); }, } }, } - self.fetch_image(url); + self.fetch_image(url, CanGc::note()); } /// Step 8-12 of html.spec.whatwg.org/multipage/#update-the-image-data - fn update_the_image_data_sync_steps(&self) { + fn update_the_image_data_sync_steps(&self, can_gc: CanGc) { let document = document_from_node(self); let window = document.window(); let task_source = window.task_manager().dom_manipulation_task_source(); @@ -871,8 +887,8 @@ impl HTMLImageElement { // Step 8 Some(data) => data, None => { - self.abort_request(State::Broken, ImageRequestPhase::Current); - self.abort_request(State::Broken, ImageRequestPhase::Pending); + self.abort_request(State::Broken, ImageRequestPhase::Current, can_gc); + self.abort_request(State::Broken, ImageRequestPhase::Pending, CanGc::note()); // Step 9. // FIXME(nox): Why are errors silenced here? let _ = task_source.queue( @@ -903,11 +919,11 @@ impl HTMLImageElement { match parsed_url { Ok(url) => { // Step 13-17 - self.prepare_image_request(&url, &src, pixel_density); + self.prepare_image_request(&url, &src, pixel_density, can_gc); }, Err(_) => { - self.abort_request(State::Broken, ImageRequestPhase::Current); - self.abort_request(State::Broken, ImageRequestPhase::Pending); + self.abort_request(State::Broken, ImageRequestPhase::Current, can_gc); + self.abort_request(State::Broken, ImageRequestPhase::Pending, CanGc::note()); // Step 12.1-12.5. let src = src.0; // FIXME(nox): Why are errors silenced here? @@ -929,7 +945,7 @@ impl HTMLImageElement { } /// <https://html.spec.whatwg.org/multipage/#update-the-image-data> - pub fn update_the_image_data(&self) { + pub fn update_the_image_data(&self, can_gc: CanGc) { let document = document_from_node(self); let window = document.window(); let elem = self.upcast::<Element>(); @@ -990,8 +1006,16 @@ impl HTMLImageElement { width: image.width, }; // Step 6.3.2 abort requests - self.abort_request(State::CompletelyAvailable, ImageRequestPhase::Current); - self.abort_request(State::Unavailable, ImageRequestPhase::Pending); + self.abort_request( + State::CompletelyAvailable, + ImageRequestPhase::Current, + can_gc, + ); + self.abort_request( + State::Unavailable, + ImageRequestPhase::Pending, + CanGc::note(), + ); let mut current_request = self.current_request.borrow_mut(); current_request.final_url = Some(img_url.clone()); current_request.image = Some(image.clone()); @@ -1038,13 +1062,14 @@ impl HTMLImageElement { } /// Step 2-12 of <https://html.spec.whatwg.org/multipage/#img-environment-changes> - fn react_to_environment_changes_sync_steps(&self, generation: u32) { + fn react_to_environment_changes_sync_steps(&self, generation: u32, can_gc: CanGc) { // TODO reduce duplicacy of this code fn generate_cache_listener_for_element( elem: &HTMLImageElement, selected_source: String, selected_pixel_density: f64, + _can_gc: CanGc, ) -> IpcSender<PendingImageResponse> { let trusted_node = Trusted::new(elem); let (responder_sender, responder_receiver) = ipc::channel().unwrap(); @@ -1069,7 +1094,8 @@ impl HTMLImageElement { // Ignore any image response for a previous request that has been discarded. if generation == element.generation.get() { element.process_image_response_for_environment_change(image, - USVString::from(selected_source_clone), generation, selected_pixel_density); + USVString::from(selected_source_clone), generation, + selected_pixel_density, CanGc::note()); } }), &canceller, @@ -1124,6 +1150,7 @@ impl HTMLImageElement { &mut self.pending_request.borrow_mut(), &img_url, &selected_source, + CanGc::note(), ); let window = window_from_node(self); @@ -1134,6 +1161,7 @@ impl HTMLImageElement { self, selected_source.0.clone(), selected_pixel_density, + CanGc::note(), ); let cache_result = image_cache.track_image( img_url.clone(), @@ -1150,6 +1178,7 @@ impl HTMLImageElement { selected_source, generation, selected_pixel_density, + can_gc, ) }, ImageCacheResult::Available(ImageOrMetadataAvailable::MetadataAvailable(m)) => { @@ -1158,6 +1187,7 @@ impl HTMLImageElement { selected_source, generation, selected_pixel_density, + can_gc, ); }, ImageCacheResult::LoadError => { @@ -1166,6 +1196,7 @@ impl HTMLImageElement { selected_source, generation, selected_pixel_density, + can_gc, ); }, ImageCacheResult::ReadyForRequest(id) => self.fetch_request(&img_url, id), @@ -1221,6 +1252,7 @@ impl HTMLImageElement { src: USVString, generation: u32, selected_pixel_density: f64, + can_gc: CanGc, ) { let this = Trusted::new(self); let window = window_from_node(self); @@ -1231,7 +1263,7 @@ impl HTMLImageElement { let relevant_mutation = this.generation.get() != generation; // Step 15.1 if relevant_mutation { - this.abort_request(State::Unavailable, ImageRequestPhase::Pending); + this.abort_request(State::Unavailable, ImageRequestPhase::Pending, can_gc); return; } // Step 15.2 @@ -1249,7 +1281,7 @@ impl HTMLImageElement { // Step 15.5 mem::swap(&mut this.current_request.borrow_mut(), &mut pending_request); - this.abort_request(State::Unavailable, ImageRequestPhase::Pending); + this.abort_request(State::Unavailable, ImageRequestPhase::Pending, can_gc); } // Step 15.6 @@ -1326,7 +1358,7 @@ impl HTMLImageElement { pub fn Image( window: &Window, proto: Option<HandleObject>, - _can_gc: CanGc, + can_gc: CanGc, width: Option<u32>, height: Option<u32>, ) -> Fallible<DomRoot<HTMLImageElement>> { @@ -1337,6 +1369,7 @@ impl HTMLImageElement { ElementCreator::ScriptCreated, CustomElementCreationMode::Synchronous, proto, + can_gc, ); let image = DomRoot::downcast::<HTMLImageElement>(element).unwrap(); @@ -1349,7 +1382,7 @@ impl HTMLImageElement { // run update_the_image_data when the element is created. // https://html.spec.whatwg.org/multipage/#when-to-obtain-images - image.update_the_image_data(); + image.update_the_image_data(CanGc::note()); Ok(image) } @@ -1415,7 +1448,7 @@ pub enum ImageElementMicrotask { } impl MicrotaskRunnable for ImageElementMicrotask { - fn handler(&self) { + fn handler(&self, can_gc: CanGc) { match *self { ImageElementMicrotask::StableStateUpdateImageDataTask { ref elem, @@ -1424,14 +1457,14 @@ impl MicrotaskRunnable for ImageElementMicrotask { // Step 7 of https://html.spec.whatwg.org/multipage/#update-the-image-data, // stop here if other instances of this algorithm have been scheduled if elem.generation.get() == *generation { - elem.update_the_image_data_sync_steps(); + elem.update_the_image_data_sync_steps(can_gc); } }, ImageElementMicrotask::EnvironmentChangesTask { ref elem, ref generation, } => { - elem.react_to_environment_changes_sync_steps(*generation); + elem.react_to_environment_changes_sync_steps(*generation, can_gc); }, ImageElementMicrotask::DecodeTask { ref elem, @@ -1739,7 +1772,7 @@ impl VirtualMethods for HTMLImageElement { fn adopting_steps(&self, old_doc: &Document) { self.super_type().unwrap().adopting_steps(old_doc); - self.update_the_image_data(); + self.update_the_image_data(CanGc::note()); } fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) { @@ -1750,7 +1783,7 @@ impl VirtualMethods for HTMLImageElement { &local_name!("width") | &local_name!("crossorigin") | &local_name!("sizes") | - &local_name!("referrerpolicy") => self.update_the_image_data(), + &local_name!("referrerpolicy") => self.update_the_image_data(CanGc::note()), _ => {}, } } @@ -1819,7 +1852,7 @@ impl VirtualMethods for HTMLImageElement { // https://html.spec.whatwg.org/multipage/#relevant-mutations if let Some(parent) = self.upcast::<Node>().GetParentElement() { if parent.is::<HTMLPictureElement>() { - self.update_the_image_data(); + self.update_the_image_data(CanGc::note()); } } } @@ -1832,7 +1865,7 @@ impl VirtualMethods for HTMLImageElement { // The element is removed from a picture parent element // https://html.spec.whatwg.org/multipage/#relevant-mutations if context.parent.is::<HTMLPictureElement>() { - self.update_the_image_data(); + self.update_the_image_data(CanGc::note()); } } } @@ -1861,7 +1894,7 @@ impl ImageCacheListener for HTMLImageElement { } fn process_image_response(&self, response: ImageResponse) { - self.process_image_response(response); + self.process_image_response(response, CanGc::note()); } } diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 8a5889cae8f..e9c0b1e8a35 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -101,6 +101,7 @@ use crate::fetch::{create_a_potential_cors_request, FetchCanceller}; use crate::microtask::{Microtask, MicrotaskRunnable}; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; use crate::realms::{enter_realm, InRealm}; +use crate::script_runtime::CanGc; use crate::script_thread::ScriptThread; use crate::task_source::TaskSource; @@ -496,12 +497,12 @@ impl HTMLMediaElement { /// we pass true to that method again. /// /// <https://html.spec.whatwg.org/multipage/#delaying-the-load-event-flag> - pub fn delay_load_event(&self, delay: bool) { + pub fn delay_load_event(&self, delay: bool, can_gc: CanGc) { let mut blocker = self.delaying_the_load_event_flag.borrow_mut(); if delay && blocker.is_none() { *blocker = Some(LoadBlocker::new(&document_from_node(self), LoadType::Media)); } else if !delay && blocker.is_some() { - LoadBlocker::terminate(&mut blocker); + LoadBlocker::terminate(&mut blocker, can_gc); } } @@ -607,7 +608,7 @@ impl HTMLMediaElement { } // https://html.spec.whatwg.org/multipage/#ready-states - fn change_ready_state(&self, ready_state: ReadyState) { + fn change_ready_state(&self, ready_state: ReadyState, can_gc: CanGc) { let old_ready_state = self.ready_state.get(); self.ready_state.set(ready_state); @@ -638,7 +639,7 @@ impl HTMLMediaElement { task!(media_reached_current_data: move || { let this = this.root(); this.upcast::<EventTarget>().fire_event(atom!("loadeddata")); - this.delay_load_event(false); + this.delay_load_event(false, can_gc); }), window.upcast(), ); @@ -697,7 +698,7 @@ impl HTMLMediaElement { } // https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm - fn invoke_resource_selection_algorithm(&self) { + fn invoke_resource_selection_algorithm(&self, can_gc: CanGc) { // Step 1. self.network_state.set(NetworkState::NoSource); @@ -705,7 +706,7 @@ impl HTMLMediaElement { self.set_show_poster(true); // Step 3. - self.delay_load_event(true); + self.delay_load_event(true, can_gc); // Step 4. // If the resource selection mode in the synchronous section is @@ -728,7 +729,7 @@ impl HTMLMediaElement { } // https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm - fn resource_selection_algorithm_sync(&self, base_url: ServoUrl) { + fn resource_selection_algorithm_sync(&self, base_url: ServoUrl, can_gc: CanGc) { // Step 5. // FIXME(ferjm): Implement blocked_on_parser logic // https://html.spec.whatwg.org/multipage/#blocked-on-parser @@ -765,7 +766,7 @@ impl HTMLMediaElement { } else { self.network_state.set(NetworkState::Empty); // https://github.com/whatwg/html/issues/3065 - self.delay_load_event(false); + self.delay_load_event(false, can_gc); return; }; @@ -792,12 +793,12 @@ impl HTMLMediaElement { // Step 9.obj.3. // Note that the resource fetch algorithm itself takes care // of the cleanup in case of failure itself. - self.resource_fetch_algorithm(Resource::Object); + self.resource_fetch_algorithm(Resource::Object, can_gc); }, Mode::Attribute(src) => { // Step 9.attr.1. if src.is_empty() { - self.queue_dedicated_media_source_failure_steps(); + self.queue_dedicated_media_source_failure_steps(can_gc); return; } @@ -805,7 +806,7 @@ impl HTMLMediaElement { let url_record = match base_url.join(&src) { Ok(url) => url, Err(_) => { - self.queue_dedicated_media_source_failure_steps(); + self.queue_dedicated_media_source_failure_steps(can_gc); return; }, }; @@ -816,7 +817,7 @@ impl HTMLMediaElement { // Step 9.attr.4. // Note that the resource fetch algorithm itself takes care // of the cleanup in case of failure itself. - self.resource_fetch_algorithm(Resource::Url(url_record)); + self.resource_fetch_algorithm(Resource::Url(url_record), can_gc); }, // Step 9.children. Mode::Children(source) => { @@ -826,7 +827,7 @@ impl HTMLMediaElement { // Step 9.attr.2. if src.is_empty() { source.upcast::<EventTarget>().fire_event(atom!("error")); - self.queue_dedicated_media_source_failure_steps(); + self.queue_dedicated_media_source_failure_steps(can_gc); return; } // Step 9.attr.3. @@ -834,20 +835,20 @@ impl HTMLMediaElement { Ok(url) => url, Err(_) => { source.upcast::<EventTarget>().fire_event(atom!("error")); - self.queue_dedicated_media_source_failure_steps(); + self.queue_dedicated_media_source_failure_steps(can_gc); return; }, }; // Step 9.attr.8. - self.resource_fetch_algorithm(Resource::Url(url_record)); + self.resource_fetch_algorithm(Resource::Url(url_record), can_gc); }, } } - fn fetch_request(&self, offset: Option<u64>, seek_lock: Option<SeekLock>) { + fn fetch_request(&self, offset: Option<u64>, seek_lock: Option<SeekLock>, can_gc: CanGc) { if self.resource_url.borrow().is_none() && self.blob_url.borrow().is_none() { eprintln!("Missing request url"); - self.queue_dedicated_media_source_failure_steps(); + self.queue_dedicated_media_source_failure_steps(can_gc); return; } @@ -919,10 +920,10 @@ impl HTMLMediaElement { } // https://html.spec.whatwg.org/multipage/#concept-media-load-resource - fn resource_fetch_algorithm(&self, resource: Resource) { - if let Err(e) = self.setup_media_player(&resource) { + fn resource_fetch_algorithm(&self, resource: Resource, can_gc: CanGc) { + if let Err(e) = self.setup_media_player(&resource, CanGc::note()) { eprintln!("Setup media player error {:?}", e); - self.queue_dedicated_media_source_failure_steps(); + self.queue_dedicated_media_source_failure_steps(CanGc::note()); return; } @@ -955,7 +956,7 @@ impl HTMLMediaElement { .media_element_task_source() .queue( task!(set_media_delay_load_event_flag_to_false: move || { - this.root().delay_load_event(false); + this.root().delay_load_event(false, can_gc); }), window.upcast(), ) @@ -974,7 +975,7 @@ impl HTMLMediaElement { // Step 4.remote.2. *self.resource_url.borrow_mut() = Some(url); - self.fetch_request(None, None); + self.fetch_request(None, None, can_gc); }, Resource::Object => { if let Some(ref src_object) = *self.src_object.borrow() { @@ -983,7 +984,7 @@ impl HTMLMediaElement { let blob_url = URL::CreateObjectURL(&self.global(), blob); *self.blob_url.borrow_mut() = Some(ServoUrl::parse(&blob_url).expect("infallible")); - self.fetch_request(None, None); + self.fetch_request(None, None, can_gc); }, SrcObject::MediaStream(ref stream) => { let tracks = &*stream.get_tracks(); @@ -998,7 +999,7 @@ impl HTMLMediaElement { .set_stream(&track.id(), pos == tracks.len() - 1) .is_err() { - self.queue_dedicated_media_source_failure_steps(); + self.queue_dedicated_media_source_failure_steps(CanGc::note()); } } }, @@ -1011,7 +1012,7 @@ impl HTMLMediaElement { /// Queues a task to run the [dedicated media source failure steps][steps]. /// /// [steps]: https://html.spec.whatwg.org/multipage/#dedicated-media-source-failure-steps - fn queue_dedicated_media_source_failure_steps(&self) { + fn queue_dedicated_media_source_failure_steps(&self, can_gc: CanGc) { let window = window_from_node(self); let this = Trusted::new(self); let generation_id = self.generation_id.get(); @@ -1056,7 +1057,7 @@ impl HTMLMediaElement { }); // Step 7. - this.delay_load_event(false); + this.delay_load_event(false, can_gc); }), window.upcast(), ); @@ -1104,7 +1105,7 @@ impl HTMLMediaElement { } // https://html.spec.whatwg.org/multipage/#media-element-load-algorithm - fn media_element_load_algorithm(&self) { + fn media_element_load_algorithm(&self, can_gc: CanGc) { // Reset the flag that signals whether loadeddata was ever fired for // this invokation of the load algorithm. self.fired_loadeddata_event.set(false); @@ -1145,7 +1146,7 @@ impl HTMLMediaElement { // Step 6.5. if self.ready_state.get() != ReadyState::HaveNothing { - self.change_ready_state(ReadyState::HaveNothing); + self.change_ready_state(ReadyState::HaveNothing, can_gc); } // Step 6.6. @@ -1185,7 +1186,7 @@ impl HTMLMediaElement { self.autoplaying.set(true); // Step 9. - self.invoke_resource_selection_algorithm(); + self.invoke_resource_selection_algorithm(CanGc::note()); // Step 10. // FIXME(nox): Stop playback of any previously running media resource. @@ -1245,14 +1246,14 @@ impl HTMLMediaElement { /// Handles insertion of `source` children. /// /// <https://html.spec.whatwg.org/multipage/#the-source-element:nodes-are-inserted> - pub fn handle_source_child_insertion(&self) { + pub fn handle_source_child_insertion(&self, can_gc: CanGc) { if self.upcast::<Element>().has_attribute(&local_name!("src")) { return; } if self.network_state.get() != NetworkState::Empty { return; } - self.media_element_load_algorithm(); + self.media_element_load_algorithm(can_gc); } // https://html.spec.whatwg.org/multipage/#dom-media-seek @@ -1351,7 +1352,7 @@ impl HTMLMediaElement { } } - fn setup_media_player(&self, resource: &Resource) -> Result<(), ()> { + fn setup_media_player(&self, resource: &Resource, _can_gc: CanGc) -> Result<(), ()> { let stream_type = match *resource { Resource::Object => { if let Some(ref src_object) = *self.src_object.borrow() { @@ -1402,7 +1403,7 @@ impl HTMLMediaElement { let this = trusted_node.clone(); if let Err(err) = task_source.queue_with_canceller( task!(handle_player_event: move || { - this.root().handle_player_event(&event); + this.root().handle_player_event(&event, CanGc::note()); }), &canceller, ) { @@ -1495,14 +1496,14 @@ impl HTMLMediaElement { } } - fn handle_player_event(&self, event: &PlayerEvent) { + fn handle_player_event(&self, event: &PlayerEvent, can_gc: CanGc) { match *event { PlayerEvent::EndOfStream => { // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list // => "If the media data can be fetched but is found by inspection to be in // an unsupported format, or can otherwise not be rendered at all" if self.ready_state.get() < ReadyState::HaveMetadata { - self.queue_dedicated_media_source_failure_steps(); + self.queue_dedicated_media_source_failure_steps(can_gc); } else { // https://html.spec.whatwg.org/multipage/#reaches-the-end match self.direction_of_playback() { @@ -1548,7 +1549,7 @@ impl HTMLMediaElement { ); // https://html.spec.whatwg.org/multipage/#dom-media-have_current_data - self.change_ready_state(ReadyState::HaveCurrentData); + self.change_ready_state(ReadyState::HaveCurrentData, can_gc); } }, @@ -1592,7 +1593,7 @@ impl HTMLMediaElement { self.network_state.set(NetworkState::Idle); // 4. Set the element's delaying-the-load-event flag to false. This stops delaying the load event. - self.delay_load_event(false); + self.delay_load_event(false, can_gc); // 5. Fire an event named error at the media element. self.upcast::<EventTarget>().fire_event(atom!("error")); @@ -1752,7 +1753,7 @@ impl HTMLMediaElement { } // Step 6. - self.change_ready_state(ReadyState::HaveMetadata); + self.change_ready_state(ReadyState::HaveMetadata, can_gc); // Step 7. let mut jumped = false; @@ -1822,7 +1823,7 @@ impl HTMLMediaElement { } }, PlayerEvent::EnoughData => { - self.change_ready_state(ReadyState::HaveEnoughData); + self.change_ready_state(ReadyState::HaveEnoughData, can_gc); // The player has enough data and it is asking us to stop pushing // bytes, so we cancel the ongoing fetch request iff we are able @@ -1855,7 +1856,7 @@ impl HTMLMediaElement { )); }, PlayerEvent::SeekData(p, ref seek_lock) => { - self.fetch_request(Some(p), Some(seek_lock.clone())); + self.fetch_request(Some(p), Some(seek_lock.clone()), can_gc); }, PlayerEvent::SeekDone(_) => { // Continuation of @@ -1874,7 +1875,7 @@ impl HTMLMediaElement { PlaybackState::Paused => { media_session_playback_state = MediaSessionPlaybackState::Paused; if self.ready_state.get() == ReadyState::HaveMetadata { - self.change_ready_state(ReadyState::HaveEnoughData); + self.change_ready_state(ReadyState::HaveEnoughData, can_gc); } }, PlaybackState::Playing => { @@ -1984,13 +1985,13 @@ impl HTMLMediaElement { /// selected by the servo-media Player instance. However, in some cases, like /// the WebAudio MediaElementAudioSourceNode, we need to set a custom audio /// renderer. - pub fn set_audio_renderer(&self, audio_renderer: Arc<Mutex<dyn AudioRenderer>>) { + pub fn set_audio_renderer(&self, audio_renderer: Arc<Mutex<dyn AudioRenderer>>, can_gc: CanGc) { *self.audio_renderer.borrow_mut() = Some(audio_renderer); if let Some(ref player) = *self.player.borrow() { if let Err(e) = player.lock().unwrap().stop() { eprintln!("Could not stop player {:?}", e); } - self.media_element_load_algorithm(); + self.media_element_load_algorithm(can_gc); } } @@ -2141,9 +2142,9 @@ impl HTMLMediaElementMethods for HTMLMediaElement { } // https://html.spec.whatwg.org/multipage/#dom-media-srcobject - fn SetSrcObject(&self, value: Option<MediaStreamOrBlob>) { + fn SetSrcObject(&self, value: Option<MediaStreamOrBlob>, can_gc: CanGc) { *self.src_object.borrow_mut() = value.map(|value| value.into()); - self.media_element_load_algorithm(); + self.media_element_load_algorithm(can_gc); } // https://html.spec.whatwg.org/multipage/#attr-media-preload @@ -2158,8 +2159,8 @@ impl HTMLMediaElementMethods for HTMLMediaElement { } // https://html.spec.whatwg.org/multipage/#dom-media-load - fn Load(&self) { - self.media_element_load_algorithm(); + fn Load(&self, can_gc: CanGc) { + self.media_element_load_algorithm(can_gc); } // https://html.spec.whatwg.org/multipage/#dom-navigator-canplaytype @@ -2177,7 +2178,7 @@ impl HTMLMediaElementMethods for HTMLMediaElement { } // https://html.spec.whatwg.org/multipage/#dom-media-play - fn Play(&self, comp: InRealm) -> Rc<Promise> { + fn Play(&self, comp: InRealm, can_gc: CanGc) -> Rc<Promise> { let promise = Promise::new_in_current_realm(comp); // Step 1. // FIXME(nox): Reject promise if not allowed to play. @@ -2197,7 +2198,7 @@ impl HTMLMediaElementMethods for HTMLMediaElement { // Step 4. if self.network_state.get() == NetworkState::Empty { - self.invoke_resource_selection_algorithm(); + self.invoke_resource_selection_algorithm(can_gc); } // Step 5. @@ -2267,10 +2268,10 @@ impl HTMLMediaElementMethods for HTMLMediaElement { } // https://html.spec.whatwg.org/multipage/#dom-media-pause - fn Pause(&self) { + fn Pause(&self, can_gc: CanGc) { // Step 1 if self.network_state.get() == NetworkState::Empty { - self.invoke_resource_selection_algorithm(); + self.invoke_resource_selection_algorithm(can_gc); } // Step 2 @@ -2489,7 +2490,7 @@ impl VirtualMethods for HTMLMediaElement { if mutation.new_value(attr).is_none() { return; } - self.media_element_load_algorithm(); + self.media_element_load_algorithm(CanGc::note()); }, local_name!("controls") => { if mutation.new_value(attr).is_some() { @@ -2552,7 +2553,7 @@ pub enum MediaElementMicrotask { } impl MicrotaskRunnable for MediaElementMicrotask { - fn handler(&self) { + fn handler(&self, can_gc: CanGc) { match self { &MediaElementMicrotask::ResourceSelectionTask { ref elem, @@ -2560,7 +2561,7 @@ impl MicrotaskRunnable for MediaElementMicrotask { ref base_url, } => { if generation_id == elem.generation_id.get() { - elem.resource_selection_algorithm_sync(base_url.clone()); + elem.resource_selection_algorithm_sync(base_url.clone(), can_gc); } }, MediaElementMicrotask::PauseIfNotInDocumentTask { elem } => { @@ -2752,7 +2753,7 @@ impl FetchResponseListener for HTMLMediaElementFetchListener { if let Some(ref mut current_fetch_context) = *elem.current_fetch_context.borrow_mut() { current_fetch_context.cancel(CancelReason::Error); } - elem.queue_dedicated_media_source_failure_steps(); + elem.queue_dedicated_media_source_failure_steps(CanGc::note()); } } @@ -2878,13 +2879,13 @@ impl FetchResponseListener for HTMLMediaElementFetchListener { elem.network_state.set(NetworkState::Idle); // Step 4. - elem.delay_load_event(false); + elem.delay_load_event(false, CanGc::note()); // Step 5 elem.upcast::<EventTarget>().fire_event(atom!("error")); } else { // => "If the media data cannot be fetched at all..." - elem.queue_dedicated_media_source_failure_steps(); + elem.queue_dedicated_media_source_failure_steps(CanGc::note()); } } diff --git a/components/script/dom/htmloptionelement.rs b/components/script/dom/htmloptionelement.rs index e4916093fcb..29bf795a0f9 100644 --- a/components/script/dom/htmloptionelement.rs +++ b/components/script/dom/htmloptionelement.rs @@ -87,7 +87,7 @@ impl HTMLOptionElement { pub fn Option( window: &Window, proto: Option<HandleObject>, - _can_gc: CanGc, + can_gc: CanGc, text: DOMString, value: Option<DOMString>, default_selected: bool, @@ -100,6 +100,7 @@ impl HTMLOptionElement { ElementCreator::ScriptCreated, CustomElementCreationMode::Synchronous, proto, + can_gc, ); let option = DomRoot::downcast::<HTMLOptionElement>(element).unwrap(); diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index ff5ca63c0eb..f814ef47fa9 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -66,6 +66,7 @@ use crate::realms::enter_realm; use crate::script_module::{ fetch_external_module_script, fetch_inline_module_script, ModuleOwner, ScriptFetchOptions, }; +use crate::script_runtime::CanGc; use crate::task::TaskCanceller; use crate::task_source::dom_manipulation::DOMManipulationTaskSource; use crate::task_source::{TaskSource, TaskSourceName}; @@ -304,6 +305,7 @@ fn finish_fetching_a_classic_script( script_kind: ExternalScriptKind, url: ServoUrl, load: ScriptResult, + can_gc: CanGc, ) { // Step 11, Asynchronously complete this algorithm with script, // which refers to step 26.6 "When the chosen algorithm asynchronously completes", @@ -315,11 +317,11 @@ fn finish_fetching_a_classic_script( ExternalScriptKind::AsapInOrder => document.asap_in_order_script_loaded(elem, load), ExternalScriptKind::Deferred => document.deferred_script_loaded(elem, load), ExternalScriptKind::ParsingBlocking => { - document.pending_parsing_blocking_script_loaded(elem, load) + document.pending_parsing_blocking_script_loaded(elem, load, can_gc) }, } - document.finish_load(LoadType::Script(url)); + document.finish_load(LoadType::Script(url), CanGc::note()); } pub type ScriptResult = Result<ScriptOrigin, NoTrace<NetworkError>>; @@ -397,6 +399,7 @@ impl FetchResponseListener for ClassicContext { self.kind, self.url.clone(), Err(NoTrace(err.clone())), + CanGc::note(), ); return; }, @@ -457,7 +460,13 @@ impl FetchResponseListener for ClassicContext { self.fetch_options.clone(), ScriptType::Classic, ); - finish_fetching_a_classic_script(&elem, self.kind, self.url.clone(), Ok(load)); + finish_fetching_a_classic_script( + &elem, + self.kind, + self.url.clone(), + Ok(load), + CanGc::note(), + ); //} } diff --git a/components/script/dom/htmlsourceelement.rs b/components/script/dom/htmlsourceelement.rs index 0ef9d96df2d..e50ad5c131a 100644 --- a/components/script/dom/htmlsourceelement.rs +++ b/components/script/dom/htmlsourceelement.rs @@ -19,6 +19,7 @@ use crate::dom::htmlimageelement::HTMLImageElement; use crate::dom::htmlmediaelement::HTMLMediaElement; use crate::dom::node::{BindContext, Node, UnbindContext}; use crate::dom::virtualmethods::VirtualMethods; +use crate::script_runtime::CanGc; #[dom_struct] pub struct HTMLSourceElement { @@ -54,10 +55,11 @@ impl HTMLSourceElement { fn iterate_next_html_image_element_siblings( next_siblings_iterator: impl Iterator<Item = Root<Dom<Node>>>, + _can_gc: CanGc, ) { for next_sibling in next_siblings_iterator { if let Some(html_image_element_sibling) = next_sibling.downcast::<HTMLImageElement>() { - html_image_element_sibling.update_the_image_data(); + html_image_element_sibling.update_the_image_data(CanGc::note()); } } } @@ -76,7 +78,10 @@ impl VirtualMethods for HTMLSourceElement { &local_name!("media") | &local_name!("type") => { let next_sibling_iterator = self.upcast::<Node>().following_siblings(); - HTMLSourceElement::iterate_next_html_image_element_siblings(next_sibling_iterator); + HTMLSourceElement::iterate_next_html_image_element_siblings( + next_sibling_iterator, + CanGc::note(), + ); }, _ => {}, } @@ -87,17 +92,23 @@ impl VirtualMethods for HTMLSourceElement { self.super_type().unwrap().bind_to_tree(context); let parent = self.upcast::<Node>().GetParentNode().unwrap(); if let Some(media) = parent.downcast::<HTMLMediaElement>() { - media.handle_source_child_insertion(); + media.handle_source_child_insertion(CanGc::note()); } let next_sibling_iterator = self.upcast::<Node>().following_siblings(); - HTMLSourceElement::iterate_next_html_image_element_siblings(next_sibling_iterator); + HTMLSourceElement::iterate_next_html_image_element_siblings( + next_sibling_iterator, + CanGc::note(), + ); } fn unbind_from_tree(&self, context: &UnbindContext) { self.super_type().unwrap().unbind_from_tree(context); if let Some(next_sibling) = context.next_sibling { let next_sibling_iterator = next_sibling.inclusively_following_siblings(); - HTMLSourceElement::iterate_next_html_image_element_siblings(next_sibling_iterator); + HTMLSourceElement::iterate_next_html_image_element_siblings( + next_sibling_iterator, + CanGc::note(), + ); } } } diff --git a/components/script/dom/htmltemplateelement.rs b/components/script/dom/htmltemplateelement.rs index fcfd06ad74d..02b8358fd0b 100644 --- a/components/script/dom/htmltemplateelement.rs +++ b/components/script/dom/htmltemplateelement.rs @@ -16,6 +16,7 @@ use crate::dom::documentfragment::DocumentFragment; use crate::dom::htmlelement::HTMLElement; use crate::dom::node::{document_from_node, CloneChildrenFlag, Node}; use crate::dom::virtualmethods::VirtualMethods; +use crate::script_runtime::CanGc; #[dom_struct] pub struct HTMLTemplateElement { @@ -59,10 +60,10 @@ impl HTMLTemplateElement { impl HTMLTemplateElementMethods for HTMLTemplateElement { /// <https://html.spec.whatwg.org/multipage/#dom-template-content> - fn Content(&self) -> DomRoot<DocumentFragment> { + fn Content(&self, can_gc: CanGc) -> DomRoot<DocumentFragment> { self.contents.or_init(|| { let doc = document_from_node(self); - doc.appropriate_template_contents_owner_document() + doc.appropriate_template_contents_owner_document(can_gc) .CreateDocumentFragment() }) } @@ -77,9 +78,10 @@ impl VirtualMethods for HTMLTemplateElement { fn adopting_steps(&self, old_doc: &Document) { self.super_type().unwrap().adopting_steps(old_doc); // Step 1. - let doc = document_from_node(self).appropriate_template_contents_owner_document(); + let doc = + document_from_node(self).appropriate_template_contents_owner_document(CanGc::note()); // Step 2. - Node::adopt(self.Content().upcast(), &doc); + Node::adopt(self.Content(CanGc::note()).upcast(), &doc); } /// <https://html.spec.whatwg.org/multipage/#the-template-element:concept-node-clone-ext> @@ -98,13 +100,14 @@ impl VirtualMethods for HTMLTemplateElement { } let copy = copy.downcast::<HTMLTemplateElement>().unwrap(); // Steps 2-3. - let copy_contents = DomRoot::upcast::<Node>(copy.Content()); + let copy_contents = DomRoot::upcast::<Node>(copy.Content(CanGc::note())); let copy_contents_doc = copy_contents.owner_doc(); - for child in self.Content().upcast::<Node>().children() { + for child in self.Content(CanGc::note()).upcast::<Node>().children() { let copy_child = Node::clone( &child, Some(©_contents_doc), CloneChildrenFlag::CloneChildren, + CanGc::note(), ); copy_contents.AppendChild(©_child).unwrap(); } diff --git a/components/script/dom/htmlvideoelement.rs b/components/script/dom/htmlvideoelement.rs index b09503627c5..61ee1a75e2e 100644 --- a/components/script/dom/htmlvideoelement.rs +++ b/components/script/dom/htmlvideoelement.rs @@ -42,6 +42,7 @@ use crate::dom::virtualmethods::VirtualMethods; use crate::fetch::FetchCanceller; use crate::image_listener::{generate_cache_listener_for_element, ImageCacheListener}; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; +use crate::script_runtime::CanGc; const DEFAULT_WIDTH: u32 = 300; const DEFAULT_HEIGHT: u32 = 150; @@ -137,7 +138,7 @@ impl HTMLVideoElement { } /// <https://html.spec.whatwg.org/multipage/#poster-frame> - fn fetch_poster_frame(&self, poster_url: &str) { + fn fetch_poster_frame(&self, poster_url: &str, can_gc: CanGc) { // Step 1. let cancel_receiver = self.poster_frame_canceller.borrow_mut().initialize(); self.generation_id.set(self.generation_id.get() + 1); @@ -176,7 +177,7 @@ impl HTMLVideoElement { self.process_image_response(ImageResponse::Loaded(image, url)); }, ImageCacheResult::ReadyForRequest(id) => { - self.do_fetch_poster_frame(poster_url, id, cancel_receiver) + self.do_fetch_poster_frame(poster_url, id, cancel_receiver, can_gc) }, _ => (), } @@ -188,6 +189,7 @@ impl HTMLVideoElement { poster_url: ServoUrl, id: PendingImageId, cancel_receiver: ipc::IpcReceiver<()>, + can_gc: CanGc, ) { // Continuation of step 4. let document = document_from_node(self); @@ -205,7 +207,7 @@ impl HTMLVideoElement { // (which triggers no media load algorithm unless a explicit call to .load() is done) // will block the document's load event forever. let mut blocker = self.load_blocker.borrow_mut(); - LoadBlocker::terminate(&mut blocker); + LoadBlocker::terminate(&mut blocker, can_gc); *blocker = Some(LoadBlocker::new( &document_from_node(self), LoadType::Image(poster_url.clone()), @@ -280,7 +282,7 @@ impl VirtualMethods for HTMLVideoElement { if let Some(new_value) = mutation.new_value(attr) { if attr.local_name() == &local_name!("poster") { - self.fetch_poster_frame(&new_value); + self.fetch_poster_frame(&new_value, CanGc::note()); } } } @@ -296,13 +298,13 @@ impl ImageCacheListener for HTMLVideoElement { ImageResponse::Loaded(image, url) => { debug!("Loaded poster image for video element: {:?}", url); self.htmlmediaelement.process_poster_image_loaded(image); - LoadBlocker::terminate(&mut self.load_blocker.borrow_mut()); + LoadBlocker::terminate(&mut self.load_blocker.borrow_mut(), CanGc::note()); }, ImageResponse::MetadataLoaded(..) => {}, // The image cache may have loaded a placeholder for an invalid poster url ImageResponse::PlaceholderLoaded(..) | ImageResponse::None => { // A failed load should unblock the document load. - LoadBlocker::terminate(&mut self.load_blocker.borrow_mut()); + LoadBlocker::terminate(&mut self.load_blocker.borrow_mut(), CanGc::note()); }, } } diff --git a/components/script/dom/mediaelementaudiosourcenode.rs b/components/script/dom/mediaelementaudiosourcenode.rs index 7eb4486e8a4..c1938479e3f 100644 --- a/components/script/dom/mediaelementaudiosourcenode.rs +++ b/components/script/dom/mediaelementaudiosourcenode.rs @@ -32,6 +32,7 @@ impl MediaElementAudioSourceNode { fn new_inherited( context: &AudioContext, media_element: &HTMLMediaElement, + can_gc: CanGc, ) -> Fallible<MediaElementAudioSourceNode> { let node = AudioNode::new_inherited( AudioNodeInit::MediaElementSourceNode, @@ -45,7 +46,7 @@ impl MediaElementAudioSourceNode { MediaElementSourceNodeMessage::GetAudioRenderer(sender), )); let audio_renderer = receiver.recv().unwrap(); - media_element.set_audio_renderer(audio_renderer); + media_element.set_audio_renderer(audio_renderer, can_gc); let media_element = Dom::from_ref(media_element); Ok(MediaElementAudioSourceNode { node, @@ -69,12 +70,12 @@ impl MediaElementAudioSourceNode { media_element: &HTMLMediaElement, can_gc: CanGc, ) -> Fallible<DomRoot<MediaElementAudioSourceNode>> { - let node = MediaElementAudioSourceNode::new_inherited(context, media_element)?; + let node = MediaElementAudioSourceNode::new_inherited(context, media_element, can_gc)?; Ok(reflect_dom_object_with_proto( Box::new(node), window, proto, - can_gc, + CanGc::note(), )) } diff --git a/components/script/dom/mediasession.rs b/components/script/dom/mediasession.rs index 1f0e3392436..6fc045ca3eb 100644 --- a/components/script/dom/mediasession.rs +++ b/components/script/dom/mediasession.rs @@ -28,6 +28,7 @@ use crate::dom::htmlmediaelement::HTMLMediaElement; use crate::dom::mediametadata::MediaMetadata; use crate::dom::window::Window; use crate::realms::{enter_realm, InRealm}; +use crate::script_runtime::CanGc; #[dom_struct] pub struct MediaSession { @@ -67,7 +68,7 @@ impl MediaSession { self.media_instance.set(Some(media_instance)); } - pub fn handle_action(&self, action: MediaSessionActionType) { + pub fn handle_action(&self, action: MediaSessionActionType, can_gc: CanGc) { debug!("Handle media session action {:?}", action); if let Some(handler) = self.action_handlers.borrow().get(&action) { @@ -82,10 +83,10 @@ impl MediaSession { match action { MediaSessionActionType::Play => { let realm = enter_realm(self); - media.Play(InRealm::Entered(&realm)); + media.Play(InRealm::Entered(&realm), can_gc); }, MediaSessionActionType::Pause => { - media.Pause(); + media.Pause(can_gc); }, MediaSessionActionType::SeekBackward => {}, MediaSessionActionType::SeekForward => {}, diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index f167b75a81d..6122db3221a 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -2240,6 +2240,7 @@ impl Node { node: &Node, maybe_doc: Option<&Document>, clone_children: CloneChildrenFlag, + can_gc: CanGc, ) -> DomRoot<Node> { // Step 1. let document = match maybe_doc { @@ -2306,6 +2307,7 @@ impl Node { None, document.status_code(), Default::default(), + CanGc::note(), ); DomRoot::upcast::<Node>(document) }, @@ -2323,6 +2325,7 @@ impl Node { ElementCreator::ScriptCreated, CustomElementCreationMode::Asynchronous, None, + can_gc, ); DomRoot::upcast::<Node>(element) }, @@ -2366,7 +2369,8 @@ impl Node { // Step 6. if clone_children == CloneChildrenFlag::CloneChildren { for child in node.children() { - let child_copy = Node::clone(&child, Some(&document), clone_children); + let child_copy = + Node::clone(&child, Some(&document), clone_children, CanGc::note()); let _inserted_node = Node::pre_insert(&child_copy, ©, None); } } @@ -2816,7 +2820,7 @@ impl NodeMethods for Node { } /// <https://dom.spec.whatwg.org/#dom-node-clonenode> - fn CloneNode(&self, deep: bool) -> Fallible<DomRoot<Node>> { + fn CloneNode(&self, deep: bool, can_gc: CanGc) -> Fallible<DomRoot<Node>> { if deep && self.is::<ShadowRoot>() { return Err(Error::NotSupported); } @@ -2828,6 +2832,7 @@ impl NodeMethods for Node { } else { CloneChildrenFlag::DoNotCloneChildren }, + can_gc, )) } diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs index f2b828927cb..d686da407aa 100644 --- a/components/script/dom/range.rs +++ b/components/script/dom/range.rs @@ -87,6 +87,7 @@ impl Range { start_offset: u32, end_container: &Node, end_offset: u32, + can_gc: CanGc, ) -> DomRoot<Range> { Self::new_with_proto( document, @@ -95,7 +96,7 @@ impl Range { start_offset, end_container, end_offset, - CanGc::note(), + can_gc, ) } @@ -482,7 +483,7 @@ impl RangeMethods for Range { } /// <https://dom.spec.whatwg.org/#dom-range-clonerange> - fn CloneRange(&self) -> DomRoot<Range> { + fn CloneRange(&self, can_gc: CanGc) -> DomRoot<Range> { let start_node = self.start_container(); let owner_doc = start_node.owner_doc(); Range::new( @@ -491,6 +492,7 @@ impl RangeMethods for Range { self.start_offset(), &self.end_container(), self.end_offset(), + can_gc, ) } @@ -552,7 +554,7 @@ impl RangeMethods for Range { /// <https://dom.spec.whatwg.org/#dom-range-clonecontents> /// <https://dom.spec.whatwg.org/#concept-range-clone> - fn CloneContents(&self) -> Fallible<DomRoot<DocumentFragment>> { + fn CloneContents(&self, can_gc: CanGc) -> Fallible<DomRoot<DocumentFragment>> { // Step 3. let start_node = self.start_container(); let start_offset = self.start_offset(); @@ -598,7 +600,7 @@ impl RangeMethods for Range { fragment.upcast::<Node>().AppendChild(&clone)?; } else { // Step 14.1. - let clone = child.CloneNode(/* deep */ false)?; + let clone = child.CloneNode(/* deep */ false, CanGc::note())?; // Step 14.2. fragment.upcast::<Node>().AppendChild(&clone)?; // Step 14.3. @@ -608,9 +610,10 @@ impl RangeMethods for Range { start_offset, &child, child.len(), + can_gc, ); // Step 14.4. - let subfragment = subrange.CloneContents()?; + let subfragment = subrange.CloneContents(CanGc::note())?; // Step 14.5. clone.AppendChild(subfragment.upcast())?; } @@ -619,7 +622,7 @@ impl RangeMethods for Range { // Step 15. for child in contained_children { // Step 15.1. - let clone = child.CloneNode(/* deep */ true)?; + let clone = child.CloneNode(/* deep */ true, CanGc::note())?; // Step 15.2. fragment.upcast::<Node>().AppendChild(&clone)?; } @@ -635,13 +638,20 @@ impl RangeMethods for Range { fragment.upcast::<Node>().AppendChild(&clone)?; } else { // Step 17.1. - let clone = child.CloneNode(/* deep */ false)?; + let clone = child.CloneNode(/* deep */ false, CanGc::note())?; // Step 17.2. fragment.upcast::<Node>().AppendChild(&clone)?; // Step 17.3. - let subrange = Range::new(&clone.owner_doc(), &child, 0, &end_node, end_offset); + let subrange = Range::new( + &clone.owner_doc(), + &child, + 0, + &end_node, + end_offset, + CanGc::note(), + ); // Step 17.4. - let subfragment = subrange.CloneContents()?; + let subfragment = subrange.CloneContents(CanGc::note())?; // Step 17.5. clone.AppendChild(subfragment.upcast())?; } @@ -653,7 +663,7 @@ impl RangeMethods for Range { /// <https://dom.spec.whatwg.org/#dom-range-extractcontents> /// <https://dom.spec.whatwg.org/#concept-range-extract> - fn ExtractContents(&self) -> Fallible<DomRoot<DocumentFragment>> { + fn ExtractContents(&self, can_gc: CanGc) -> Fallible<DomRoot<DocumentFragment>> { // Step 3. let start_node = self.start_container(); let start_offset = self.start_offset(); @@ -671,7 +681,7 @@ impl RangeMethods 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)?; + let clone = end_node.CloneNode(/* deep */ true, CanGc::note())?; // Step 4.2. let text = end_data.SubstringData(start_offset, end_offset - start_offset); clone @@ -712,7 +722,7 @@ impl RangeMethods for Range { if let Some(start_data) = child.downcast::<CharacterData>() { assert!(child == start_node); // Step 15.1. - let clone = start_node.CloneNode(/* deep */ true)?; + let clone = start_node.CloneNode(/* deep */ true, CanGc::note())?; // Step 15.2. let text = start_data.SubstringData(start_offset, start_node.len() - start_offset); clone @@ -729,7 +739,7 @@ impl RangeMethods for Range { )?; } else { // Step 16.1. - let clone = child.CloneNode(/* deep */ false)?; + let clone = child.CloneNode(/* deep */ false, CanGc::note())?; // Step 16.2. fragment.upcast::<Node>().AppendChild(&clone)?; // Step 16.3. @@ -739,9 +749,10 @@ impl RangeMethods for Range { start_offset, &child, child.len(), + can_gc, ); // Step 16.4. - let subfragment = subrange.ExtractContents()?; + let subfragment = subrange.ExtractContents(CanGc::note())?; // Step 16.5. clone.AppendChild(subfragment.upcast())?; } @@ -756,7 +767,7 @@ impl RangeMethods for Range { if let Some(end_data) = child.downcast::<CharacterData>() { assert!(child == end_node); // Step 18.1. - let clone = end_node.CloneNode(/* deep */ true)?; + let clone = end_node.CloneNode(/* deep */ true, CanGc::note())?; // Step 18.2. let text = end_data.SubstringData(0, end_offset); clone @@ -769,13 +780,20 @@ impl RangeMethods for Range { end_data.ReplaceData(0, end_offset, DOMString::new())?; } else { // Step 19.1. - let clone = child.CloneNode(/* deep */ false)?; + let clone = child.CloneNode(/* deep */ false, CanGc::note())?; // Step 19.2. fragment.upcast::<Node>().AppendChild(&clone)?; // Step 19.3. - let subrange = Range::new(&clone.owner_doc(), &child, 0, &end_node, end_offset); + let subrange = Range::new( + &clone.owner_doc(), + &child, + 0, + &end_node, + end_offset, + CanGc::note(), + ); // Step 19.4. - let subfragment = subrange.ExtractContents()?; + let subfragment = subrange.ExtractContents(CanGc::note())?; // Step 19.5. clone.AppendChild(subfragment.upcast())?; } @@ -964,7 +982,7 @@ impl RangeMethods for Range { } /// <https://dom.spec.whatwg.org/#dom-range-surroundcontents> - fn SurroundContents(&self, new_parent: &Node) -> ErrorResult { + fn SurroundContents(&self, new_parent: &Node, can_gc: CanGc) -> ErrorResult { // Step 1. let start = self.start_container(); let end = self.end_container(); @@ -989,7 +1007,7 @@ impl RangeMethods for Range { } // Step 3. - let fragment = self.ExtractContents()?; + let fragment = self.ExtractContents(can_gc)?; // Step 4. Node::replace_all(None, new_parent); @@ -1056,7 +1074,11 @@ impl RangeMethods for Range { } /// <https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#extensions-to-the-range-interface> - fn CreateContextualFragment(&self, fragment: DOMString) -> Fallible<DomRoot<DocumentFragment>> { + fn CreateContextualFragment( + &self, + fragment: DOMString, + can_gc: CanGc, + ) -> Fallible<DomRoot<DocumentFragment>> { // Step 1. let node = self.start_container(); let owner_doc = node.owner_doc(); @@ -1074,7 +1096,7 @@ impl RangeMethods for Range { let element = Element::fragment_parsing_context(&owner_doc, element.as_deref()); // Step 3. - let fragment_node = element.parse_fragment(fragment)?; + let fragment_node = element.parse_fragment(fragment, can_gc)?; // Step 4. for node in fragment_node diff --git a/components/script/dom/selection.rs b/components/script/dom/selection.rs index 7d62cb04db2..63ec919a4b3 100644 --- a/components/script/dom/selection.rs +++ b/components/script/dom/selection.rs @@ -19,6 +19,7 @@ use crate::dom::document::Document; use crate::dom::eventtarget::EventTarget; use crate::dom::node::{window_from_node, Node}; use crate::dom::range::Range; +use crate::script_runtime::CanGc; use crate::task_source::TaskSource; #[derive(Clone, Copy, JSTraceable, MallocSizeOf)] @@ -241,7 +242,7 @@ impl SelectionMethods for Selection { } // https://w3c.github.io/selection-api/#dom-selection-collapse - fn Collapse(&self, node: Option<&Node>, offset: u32) -> ErrorResult { + fn Collapse(&self, node: Option<&Node>, offset: u32, can_gc: CanGc) -> ErrorResult { if let Some(node) = node { if node.is_doctype() { // w3c/selection-api#118 @@ -258,7 +259,7 @@ impl SelectionMethods for Selection { } // Steps 4-5 - let range = Range::new(&self.document, node, offset, node, offset); + let range = Range::new(&self.document, node, offset, node, offset, can_gc); // Step 6 self.set_range(&range); @@ -276,23 +277,27 @@ impl SelectionMethods for Selection { // TODO: When implementing actual selection UI, this may be the correct // method to call as the start-of-selection action, after a // selectstart event has fired and not been cancelled. - fn SetPosition(&self, node: Option<&Node>, offset: u32) -> ErrorResult { - self.Collapse(node, offset) + fn SetPosition(&self, node: Option<&Node>, offset: u32, can_gc: CanGc) -> ErrorResult { + self.Collapse(node, offset, can_gc) } // https://w3c.github.io/selection-api/#dom-selection-collapsetostart - fn CollapseToStart(&self) -> ErrorResult { + fn CollapseToStart(&self, can_gc: CanGc) -> ErrorResult { if let Some(range) = self.range.get() { - self.Collapse(Some(&*range.start_container()), range.start_offset()) + self.Collapse( + Some(&*range.start_container()), + range.start_offset(), + can_gc, + ) } else { Err(Error::InvalidState) } } // https://w3c.github.io/selection-api/#dom-selection-collapsetoend - fn CollapseToEnd(&self) -> ErrorResult { + fn CollapseToEnd(&self, can_gc: CanGc) -> ErrorResult { if let Some(range) = self.range.get() { - self.Collapse(Some(&*range.end_container()), range.end_offset()) + self.Collapse(Some(&*range.end_container()), range.end_offset(), can_gc) } else { Err(Error::InvalidState) } @@ -301,7 +306,7 @@ impl SelectionMethods for Selection { // https://w3c.github.io/selection-api/#dom-selection-extend // TODO: When implementing actual selection UI, this may be the correct // method to call as the continue-selection action - fn Extend(&self, node: &Node, offset: u32) -> ErrorResult { + fn Extend(&self, node: &Node, offset: u32, can_gc: CanGc) -> ErrorResult { if !self.is_same_root(node) { // Step 1 return Ok(()); @@ -321,7 +326,14 @@ impl SelectionMethods for Selection { // Step 4 if !self.is_same_root(&range.start_container()) { // Step 5, and its following 8 and 9 - self.set_range(&Range::new(&self.document, node, offset, node, offset)); + self.set_range(&Range::new( + &self.document, + node, + offset, + node, + offset, + can_gc, + )); self.direction.set(Direction::Forwards); } else { let old_anchor_node = &*self.GetAnchorNode().unwrap(); // has range, therefore has anchor node @@ -341,6 +353,7 @@ impl SelectionMethods for Selection { old_anchor_offset, node, offset, + can_gc, )); self.direction.set(Direction::Forwards); } else { @@ -351,6 +364,7 @@ impl SelectionMethods for Selection { offset, old_anchor_node, old_anchor_offset, + can_gc, )); self.direction.set(Direction::Backwards); } @@ -369,6 +383,7 @@ impl SelectionMethods for Selection { anchor_offset: u32, focus_node: &Node, focus_offset: u32, + can_gc: CanGc, ) -> ErrorResult { // Step 1 if anchor_node.is_doctype() || focus_node.is_doctype() { @@ -400,6 +415,7 @@ impl SelectionMethods for Selection { focus_offset, anchor_node, anchor_offset, + can_gc, )); self.direction.set(Direction::Backwards); } else { @@ -409,6 +425,7 @@ impl SelectionMethods for Selection { anchor_offset, focus_node, focus_offset, + can_gc, )); self.direction.set(Direction::Forwards); } @@ -416,7 +433,7 @@ impl SelectionMethods for Selection { } // https://w3c.github.io/selection-api/#dom-selection-selectallchildren - fn SelectAllChildren(&self, node: &Node) -> ErrorResult { + fn SelectAllChildren(&self, node: &Node, can_gc: CanGc) -> ErrorResult { if node.is_doctype() { // w3c/selection-api#118 return Err(Error::InvalidNodeType); @@ -434,6 +451,7 @@ impl SelectionMethods for Selection { 0, node, node.children_count(), + can_gc, )); self.direction.set(Direction::Forwards); diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs index 5e0794b86a3..1b6c768a186 100644 --- a/components/script/dom/serviceworkerglobalscope.rs +++ b/components/script/dom/serviceworkerglobalscope.rs @@ -45,7 +45,7 @@ use crate::dom::workerglobalscope::WorkerGlobalScope; use crate::fetch::load_whole_resource; use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; use crate::script_runtime::{ - new_rt_and_cx, CommonScriptMsg, ContextForRequestInterrupt, JSContext as SafeJSContext, + new_rt_and_cx, CanGc, CommonScriptMsg, ContextForRequestInterrupt, JSContext as SafeJSContext, Runtime, ScriptChan, }; use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue}; @@ -295,6 +295,7 @@ impl ServiceWorkerGlobalScope { control_receiver: Receiver<ServiceWorkerControlMsg>, context_sender: Sender<ContextForRequestInterrupt>, closing: Arc<AtomicBool>, + _can_gc: CanGc, ) -> JoinHandle<()> { let ScopeThings { script_url, @@ -398,7 +399,7 @@ impl ServiceWorkerGlobalScope { // which happens after the closing flag is set to true, // or until the worker has run beyond its allocated time. while !scope.is_closing() && !global.has_timed_out() { - run_worker_event_loop(&*global, None); + run_worker_event_loop(&*global, None, CanGc::note()); } }, reporter_name, diff --git a/components/script/dom/servoparser/async_html.rs b/components/script/dom/servoparser/async_html.rs index 551692af1f8..be8adb01e09 100644 --- a/components/script/dom/servoparser/async_html.rs +++ b/components/script/dom/servoparser/async_html.rs @@ -41,6 +41,7 @@ use crate::dom::node::Node; use crate::dom::processinginstruction::ProcessingInstruction; use crate::dom::servoparser::{create_element_for_token, ElementAttribute, ParsingAlgorithm}; use crate::dom::virtualmethods::vtable_for; +use crate::script_runtime::CanGc; type ParseNodeId = usize; @@ -283,7 +284,11 @@ impl Tokenizer { tokenizer } - pub fn feed(&self, input: &BufferQueue) -> TokenizerResult<DomRoot<HTMLScriptElement>> { + pub fn feed( + &self, + input: &BufferQueue, + _can_gc: CanGc, + ) -> TokenizerResult<DomRoot<HTMLScriptElement>> { let mut send_tendrils = VecDeque::new(); while let Some(str) = input.pop_front() { send_tendrils.push_back(SendTendril::from(str)); @@ -303,7 +308,9 @@ impl Tokenizer { .recv() .expect("Unexpected channel panic in main thread.") { - ToTokenizerMsg::ProcessOperation(parse_op) => self.process_operation(parse_op), + ToTokenizerMsg::ProcessOperation(parse_op) => { + self.process_operation(parse_op, CanGc::note()) + }, ToTokenizerMsg::TokenizerResultDone { updated_input } => { let buffer_queue = create_buffer_queue(updated_input); input.replace_with(buffer_queue); @@ -323,7 +330,7 @@ impl Tokenizer { } } - pub fn end(&self) { + pub fn end(&self, _can_gc: CanGc) { self.html_tokenizer_sender .send(ToHtmlTokenizerMsg::End) .unwrap(); @@ -333,7 +340,9 @@ impl Tokenizer { .recv() .expect("Unexpected channel panic in main thread.") { - ToTokenizerMsg::ProcessOperation(parse_op) => self.process_operation(parse_op), + ToTokenizerMsg::ProcessOperation(parse_op) => { + self.process_operation(parse_op, CanGc::note()) + }, ToTokenizerMsg::TokenizerResultDone { updated_input: _ } | ToTokenizerMsg::TokenizerResultScript { script: _, @@ -364,7 +373,7 @@ impl Tokenizer { }) } - fn append_before_sibling(&self, sibling: ParseNodeId, node: NodeOrText) { + fn append_before_sibling(&self, sibling: ParseNodeId, node: NodeOrText, can_gc: CanGc) { let node = match node { NodeOrText::Node(n) => { HtmlNodeOrText::AppendNode(Dom::from_ref(&**self.get_node(&n.id))) @@ -376,10 +385,10 @@ impl Tokenizer { .GetParentNode() .expect("append_before_sibling called on node without parent"); - super::insert(parent, Some(sibling), node, self.parsing_algorithm); + super::insert(parent, Some(sibling), node, self.parsing_algorithm, can_gc); } - fn append(&self, parent: ParseNodeId, node: NodeOrText) { + fn append(&self, parent: ParseNodeId, node: NodeOrText, can_gc: CanGc) { let node = match node { NodeOrText::Node(n) => { HtmlNodeOrText::AppendNode(Dom::from_ref(&**self.get_node(&n.id))) @@ -388,7 +397,7 @@ impl Tokenizer { }; let parent = &**self.get_node(&parent); - super::insert(parent, None, node, self.parsing_algorithm); + super::insert(parent, None, node, self.parsing_algorithm, can_gc); } fn has_parent_node(&self, node: ParseNodeId) -> bool { @@ -404,7 +413,7 @@ impl Tokenizer { x.is_in_same_home_subtree(y) } - fn process_operation(&self, op: ParseOperation) { + fn process_operation(&self, op: ParseOperation, can_gc: CanGc) { let document = DomRoot::from_ref(&**self.get_node(&0)); let document = document .downcast::<Document>() @@ -415,7 +424,7 @@ impl Tokenizer { let template = target .downcast::<HTMLTemplateElement>() .expect("Tried to extract contents from non-template element while parsing"); - self.insert_node(contents, Dom::from_ref(template.Content().upcast())); + self.insert_node(contents, Dom::from_ref(template.Content(can_gc).upcast())); }, ParseOperation::CreateElement { node, @@ -433,6 +442,7 @@ impl Tokenizer { &self.document, ElementCreator::ParserCreated(current_line), ParsingAlgorithm::Normal, + can_gc, ); self.insert_node(node, Dom::from_ref(element.upcast())); }, @@ -441,10 +451,10 @@ impl Tokenizer { self.insert_node(node, Dom::from_ref(comment.upcast())); }, ParseOperation::AppendBeforeSibling { sibling, node } => { - self.append_before_sibling(sibling, node); + self.append_before_sibling(sibling, node, can_gc); }, ParseOperation::Append { parent, node } => { - self.append(parent, node); + self.append(parent, node, can_gc); }, ParseOperation::AppendBasedOnParentNode { element, @@ -452,9 +462,9 @@ impl Tokenizer { node, } => { if self.has_parent_node(element) { - self.append_before_sibling(element, node); + self.append_before_sibling(element, node, can_gc); } else { - self.append(prev_element, node); + self.append(prev_element, node, can_gc); } }, ParseOperation::AppendDoctypeToDocument { diff --git a/components/script/dom/servoparser/html.rs b/components/script/dom/servoparser/html.rs index b3184923609..a2ef2a323fd 100644 --- a/components/script/dom/servoparser/html.rs +++ b/components/script/dom/servoparser/html.rs @@ -30,6 +30,7 @@ use crate::dom::htmltemplateelement::HTMLTemplateElement; use crate::dom::node::Node; use crate::dom::processinginstruction::ProcessingInstruction; use crate::dom::servoparser::{ParsingAlgorithm, Sink}; +use crate::script_runtime::CanGc; #[derive(JSTraceable, MallocSizeOf)] #[crown::unrooted_must_root_lint::must_root] @@ -163,7 +164,7 @@ fn rev_children_iter(n: &Node) -> impl Iterator<Item = DomRoot<Node>> { } match n.downcast::<HTMLTemplateElement>() { - Some(t) => t.Content().upcast::<Node>().rev_children(), + Some(t) => t.Content(CanGc::note()).upcast::<Node>().rev_children(), None => n.rev_children(), } } diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs index f6c7af85838..958b2bbf3db 100644 --- a/components/script/dom/servoparser/mod.rs +++ b/components/script/dom/servoparser/mod.rs @@ -67,6 +67,7 @@ use crate::dom::text::Text; use crate::dom::virtualmethods::vtable_for; use crate::network_listener::PreInvoke; use crate::realms::enter_realm; +use crate::script_runtime::CanGc; use crate::script_thread::ScriptThread; mod async_html; @@ -150,7 +151,12 @@ impl ServoParser { self.can_write() } - pub fn parse_html_document(document: &Document, input: Option<DOMString>, url: ServoUrl) { + pub fn parse_html_document( + document: &Document, + input: Option<DOMString>, + url: ServoUrl, + can_gc: CanGc, + ) { let parser = if pref!(dom.servoparser.async_html_tokenizer.enabled) { ServoParser::new( document, @@ -172,7 +178,7 @@ impl ServoParser { // Set as the document's current parser and initialize with `input`, if given. if let Some(input) = input { - parser.parse_complete_string_chunk(String::from(input)); + parser.parse_complete_string_chunk(String::from(input), can_gc); } else { parser.document.set_current_parser(Some(&parser)); } @@ -182,6 +188,7 @@ impl ServoParser { pub fn parse_html_fragment( context: &Element, input: DOMString, + can_gc: CanGc, ) -> impl Iterator<Item = DomRoot<Node>> { let context_node = context.upcast::<Node>(); let context_document = context_node.owner_doc(); @@ -208,6 +215,7 @@ impl ServoParser { None, None, Default::default(), + can_gc, ); // Step 2. @@ -233,7 +241,7 @@ impl ServoParser { )), ParserKind::Normal, ); - parser.parse_complete_string_chunk(String::from(input)); + parser.parse_complete_string_chunk(String::from(input), CanGc::note()); // Step 14. let root_element = document.GetDocumentElement().expect("no document element"); @@ -257,7 +265,12 @@ impl ServoParser { document.set_current_parser(Some(&parser)); } - pub fn parse_xml_document(document: &Document, input: Option<DOMString>, url: ServoUrl) { + pub fn parse_xml_document( + document: &Document, + input: Option<DOMString>, + url: ServoUrl, + can_gc: CanGc, + ) { let parser = ServoParser::new( document, Tokenizer::Xml(self::xml::Tokenizer::new(document, url)), @@ -266,7 +279,7 @@ impl ServoParser { // Set as the document's current parser and initialize with `input`, if given. if let Some(input) = input { - parser.parse_complete_string_chunk(String::from(input)); + parser.parse_complete_string_chunk(String::from(input), can_gc); } else { parser.document.set_current_parser(Some(&parser)); } @@ -298,6 +311,7 @@ impl ServoParser { &self, script: &HTMLScriptElement, result: ScriptResult, + can_gc: CanGc, ) { assert!(self.suspended.get()); self.suspended.set(false); @@ -315,7 +329,7 @@ impl ServoParser { self.script_nesting_level.set(script_nesting_level); if !self.suspended.get() && !self.aborted.get() { - self.parse_sync(); + self.parse_sync(can_gc); } } @@ -324,7 +338,7 @@ impl ServoParser { } /// Steps 6-8 of <https://html.spec.whatwg.org/multipage/#document.write()> - pub fn write(&self, text: Vec<DOMString>) { + pub fn write(&self, text: Vec<DOMString>, _can_gc: CanGc) { assert!(self.can_write()); if self.document.has_pending_parsing_blocking_script() { @@ -347,7 +361,7 @@ impl ServoParser { input.push_back(String::from(chunk).into()); } - self.tokenize(|tokenizer| tokenizer.feed(&input)); + self.tokenize(|tokenizer| tokenizer.feed(&input, CanGc::note())); if self.suspended.get() { // Parser got suspended, insert remaining input at end of @@ -363,7 +377,7 @@ impl ServoParser { } // Steps 4-6 of https://html.spec.whatwg.org/multipage/#dom-document-close - pub fn close(&self) { + pub fn close(&self, can_gc: CanGc) { assert!(self.script_created_parser); // Step 4. @@ -375,11 +389,11 @@ impl ServoParser { } // Step 6. - self.parse_sync(); + self.parse_sync(can_gc); } // https://html.spec.whatwg.org/multipage/#abort-a-parser - pub fn abort(&self) { + pub fn abort(&self, can_gc: CanGc) { assert!(!self.aborted.get()); self.aborted.set(true); @@ -392,7 +406,7 @@ impl ServoParser { .set_ready_state(DocumentReadyState::Interactive); // Step 3. - self.tokenizer.end(); + self.tokenizer.end(can_gc); self.document.set_current_parser(None); // Step 4. @@ -499,7 +513,7 @@ impl ServoParser { self.push_tendril_input_chunk(chunk); } - fn parse_sync(&self) { + fn parse_sync(&self, can_gc: CanGc) { let metadata = TimerMetadata { url: self.document.url().as_str().into(), iframe: TimerMetadataFrameType::RootWindow, @@ -514,11 +528,11 @@ impl ServoParser { .upcast::<GlobalScope>() .time_profiler_chan() .clone(), - || self.do_parse_sync(), + || self.do_parse_sync(can_gc), ) } - fn do_parse_sync(&self) { + fn do_parse_sync(&self, _can_gc: CanGc) { assert!(self.script_input.is_empty()); // This parser will continue to parse while there is either pending input or @@ -532,7 +546,7 @@ impl ServoParser { } } } - self.tokenize(|tokenizer| tokenizer.feed(&self.network_input)); + self.tokenize(|tokenizer| tokenizer.feed(&self.network_input, CanGc::note())); if self.suspended.get() { return; @@ -541,24 +555,24 @@ impl ServoParser { assert!(self.network_input.is_empty()); if self.last_chunk_received.get() { - self.finish(); + self.finish(CanGc::note()); } } - fn parse_complete_string_chunk(&self, input: String) { + fn parse_complete_string_chunk(&self, input: String, can_gc: CanGc) { self.document.set_current_parser(Some(self)); self.push_string_input_chunk(input); self.last_chunk_received.set(true); if !self.suspended.get() { - self.parse_sync(); + self.parse_sync(can_gc); } } - fn parse_bytes_chunk(&self, input: Vec<u8>) { + fn parse_bytes_chunk(&self, input: Vec<u8>, can_gc: CanGc) { self.document.set_current_parser(Some(self)); self.push_bytes_input_chunk(input); if !self.suspended.get() { - self.parse_sync(); + self.parse_sync(can_gc); } } @@ -586,7 +600,7 @@ impl ServoParser { self.document .window() .upcast::<GlobalScope>() - .perform_a_microtask_checkpoint(); + .perform_a_microtask_checkpoint(CanGc::note()); } let script_nesting_level = self.script_nesting_level.get(); @@ -606,7 +620,7 @@ impl ServoParser { } // https://html.spec.whatwg.org/multipage/#the-end - fn finish(&self) { + fn finish(&self, can_gc: CanGc) { assert!(!self.suspended.get()); assert!(self.last_chunk_received.get()); assert!(self.script_input.is_empty()); @@ -618,12 +632,13 @@ impl ServoParser { .set_ready_state(DocumentReadyState::Interactive); // Step 2. - self.tokenizer.end(); + self.tokenizer.end(can_gc); self.document.set_current_parser(None); // Steps 3-12 are in another castle, namely finish_load. let url = self.tokenizer.url().clone(); - self.document.finish_load(LoadType::PageSource(url)); + self.document + .finish_load(LoadType::PageSource(url), CanGc::note()); } } @@ -666,18 +681,22 @@ enum Tokenizer { } impl Tokenizer { - fn feed(&self, input: &BufferQueue) -> TokenizerResult<DomRoot<HTMLScriptElement>> { + fn feed( + &self, + input: &BufferQueue, + can_gc: CanGc, + ) -> TokenizerResult<DomRoot<HTMLScriptElement>> { match *self { Tokenizer::Html(ref tokenizer) => tokenizer.feed(input), - Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.feed(input), + Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.feed(input, can_gc), Tokenizer::Xml(ref tokenizer) => tokenizer.feed(input), } } - fn end(&self) { + fn end(&self, can_gc: CanGc) { match *self { Tokenizer::Html(ref tokenizer) => tokenizer.end(), - Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.end(), + Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.end(can_gc), Tokenizer::Xml(ref tokenizer) => tokenizer.end(), } } @@ -797,7 +816,7 @@ impl FetchResponseListener for ParserContext { Some(csp_list) }); - let parser = match ScriptThread::page_headers_available(&self.id, metadata) { + let parser = match ScriptThread::page_headers_available(&self.id, metadata, CanGc::note()) { Some(parser) => parser, None => return, }; @@ -829,7 +848,7 @@ impl FetchResponseListener for ParserContext { self.is_synthesized_document = true; let page = "<html><body></body></html>".into(); parser.push_string_input_chunk(page); - parser.parse_sync(); + parser.parse_sync(CanGc::note()); let doc = &parser.document; let doc_body = DomRoot::upcast::<Node>(doc.GetBody().unwrap()); @@ -843,7 +862,7 @@ impl FetchResponseListener for ParserContext { // https://html.spec.whatwg.org/multipage/#read-text let page = "<pre>\n".into(); parser.push_string_input_chunk(page); - parser.parse_sync(); + parser.parse_sync(CanGc::note()); parser.tokenizer.set_plaintext_state(); }, (mime::TEXT, mime::HTML, _) => match error { @@ -856,21 +875,21 @@ impl FetchResponseListener for ParserContext { let page = page.replace("${secret}", &net_traits::PRIVILEGED_SECRET.to_string()); parser.push_string_input_chunk(page); - parser.parse_sync(); + parser.parse_sync(CanGc::note()); }, Some(NetworkError::Internal(reason)) => { self.is_synthesized_document = true; let page = resources::read_string(Resource::NetErrorHTML); let page = page.replace("${reason}", &reason); parser.push_string_input_chunk(page); - parser.parse_sync(); + parser.parse_sync(CanGc::note()); }, Some(NetworkError::Crash(details)) => { self.is_synthesized_document = true; let page = resources::read_string(Resource::CrashHTML); let page = page.replace("${details}", &details); parser.push_string_input_chunk(page); - parser.parse_sync(); + parser.parse_sync(CanGc::note()); }, Some(_) => {}, None => {}, @@ -888,7 +907,7 @@ impl FetchResponseListener for ParserContext { ); self.is_synthesized_document = true; parser.push_string_input_chunk(page); - parser.parse_sync(); + parser.parse_sync(CanGc::note()); }, } } @@ -905,7 +924,7 @@ impl FetchResponseListener for ParserContext { return; } let _realm = enter_realm(&*parser); - parser.parse_bytes_chunk(payload); + parser.parse_bytes_chunk(payload, CanGc::note()); } // This method is called via script_thread::handle_fetch_eof, so we must call @@ -935,7 +954,7 @@ impl FetchResponseListener for ParserContext { parser.last_chunk_received.set(true); if !parser.suspended.get() { - parser.parse_sync(); + parser.parse_sync(CanGc::note()); } // TODO: Only update if this is the current document resource. @@ -1000,6 +1019,7 @@ fn insert( reference_child: Option<&Node>, child: NodeOrText<Dom<Node>>, parsing_algorithm: ParsingAlgorithm, + can_gc: CanGc, ) { match child { NodeOrText::AppendNode(n) => { @@ -1013,7 +1033,7 @@ fn insert( } parent.InsertBefore(&n, reference_child).unwrap(); if element_in_non_fragment { - ScriptThread::pop_current_element_queue(); + ScriptThread::pop_current_element_queue(can_gc); } }, NodeOrText::AppendText(t) => { @@ -1076,7 +1096,7 @@ impl TreeSink for Sink { let template = target .downcast::<HTMLTemplateElement>() .expect("tried to get template contents of non-HTMLTemplateElement in HTML parsing"); - Dom::from_ref(template.Content().upcast()) + Dom::from_ref(template.Content(CanGc::note()).upcast()) } fn same_node(&self, x: &Dom<Node>, y: &Dom<Node>) -> bool { @@ -1110,6 +1130,7 @@ impl TreeSink for Sink { &self.document, ElementCreator::ParserCreated(self.current_line.get()), self.parsing_algorithm, + CanGc::note(), ); Dom::from_ref(element.upcast()) } @@ -1167,7 +1188,13 @@ impl TreeSink for Sink { .GetParentNode() .expect("append_before_sibling called on node without parent"); - insert(&parent, Some(sibling), new_node, self.parsing_algorithm); + insert( + &parent, + Some(sibling), + new_node, + self.parsing_algorithm, + CanGc::note(), + ); } fn parse_error(&self, msg: Cow<'static, str>) { @@ -1185,7 +1212,7 @@ impl TreeSink for Sink { #[allow(crown::unrooted_must_root)] fn append(&self, parent: &Dom<Node>, child: NodeOrText<Dom<Node>>) { - insert(parent, None, child, self.parsing_algorithm); + insert(parent, None, child, self.parsing_algorithm, CanGc::note()); } #[allow(crown::unrooted_must_root)] @@ -1289,6 +1316,7 @@ fn create_element_for_token( document: &Document, creator: ElementCreator, parsing_algorithm: ParsingAlgorithm, + can_gc: CanGc, ) -> DomRoot<Element> { // Step 3. let is = attrs @@ -1312,7 +1340,7 @@ fn create_element_for_token( document .window() .upcast::<GlobalScope>() - .perform_a_microtask_checkpoint(); + .perform_a_microtask_checkpoint(can_gc); } // Step 6.3 ScriptThread::push_new_element_queue() @@ -1325,7 +1353,15 @@ fn create_element_for_token( CustomElementCreationMode::Asynchronous }; - let element = Element::create(name, is, document, creator, creation_mode, None); + let element = Element::create( + name, + is, + document, + creator, + creation_mode, + None, + CanGc::note(), + ); // https://html.spec.whatwg.org/multipage#the-input-element:value-sanitization-algorithm-3 // says to invoke sanitization "when an input element is first created"; @@ -1353,7 +1389,7 @@ fn create_element_for_token( // Step 9. if will_execute_script { // Steps 9.1 - 9.2. - ScriptThread::pop_current_element_queue(); + ScriptThread::pop_current_element_queue(CanGc::note()); // Step 9.3. document.decrement_throw_on_dynamic_markup_insertion_counter(); } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 0540cabeab5..611fccbf974 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -144,7 +144,7 @@ use crate::layout_image::fetch_image_for_layout; use crate::microtask::MicrotaskQueue; use crate::realms::InRealm; use crate::script_runtime::{ - CommonScriptMsg, JSContext, Runtime, ScriptChan, ScriptPort, ScriptThreadEventCategory, + CanGc, CommonScriptMsg, JSContext, Runtime, ScriptChan, ScriptPort, ScriptThreadEventCategory, }; use crate::script_thread::{ ImageCacheMsg, MainThreadScriptChan, MainThreadScriptMsg, ScriptThread, @@ -676,10 +676,10 @@ impl WindowMethods for Window { } // https://html.spec.whatwg.org/multipage/#dom-window-stop - fn Stop(&self) { + fn Stop(&self, can_gc: CanGc) { // TODO: Cancel ongoing navigation. let doc = self.Document(); - doc.abort(); + doc.abort(can_gc); } // https://html.spec.whatwg.org/multipage/#dom-open diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index 0f7ea7f035b..fa04bd8cbe2 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -159,6 +159,7 @@ impl Worker { global.wgpu_id_hub(), control_receiver, context_sender, + CanGc::note(), ); let context = context_receiver diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 05f14a9b380..e8c41c08cb3 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -950,7 +950,7 @@ impl XMLHttpRequestMethods for XMLHttpRequest { #[allow(unsafe_code)] /// <https://xhr.spec.whatwg.org/#the-response-attribute> - fn Response(&self, cx: JSContext) -> JSVal { + fn Response(&self, cx: JSContext, can_gc: CanGc) -> JSVal { rooted!(in(*cx) let mut rval = UndefinedValue()); match self.response_type.get() { XMLHttpRequestResponseType::_empty | XMLHttpRequestResponseType::Text => unsafe { @@ -971,7 +971,8 @@ impl XMLHttpRequestMethods for XMLHttpRequest { }, // Step 2 XMLHttpRequestResponseType::Document => unsafe { - self.document_response().to_jsval(*cx, rval.handle_mut()); + self.document_response(can_gc) + .to_jsval(*cx, rval.handle_mut()); }, XMLHttpRequestResponseType::Json => unsafe { self.json_response(cx).to_jsval(*cx, rval.handle_mut()); @@ -1006,12 +1007,12 @@ impl XMLHttpRequestMethods for XMLHttpRequest { } /// <https://xhr.spec.whatwg.org/#the-responsexml-attribute> - fn GetResponseXML(&self) -> Fallible<Option<DomRoot<Document>>> { + fn GetResponseXML(&self, can_gc: CanGc) -> Fallible<Option<DomRoot<Document>>> { match self.response_type.get() { XMLHttpRequestResponseType::_empty | XMLHttpRequestResponseType::Document => { // Step 3 if let XMLHttpRequestState::Done = self.ready_state.get() { - Ok(self.document_response()) + Ok(self.document_response(can_gc)) } else { // Step 2 Ok(None) @@ -1367,7 +1368,7 @@ impl XMLHttpRequest { } /// <https://xhr.spec.whatwg.org/#document-response> - fn document_response(&self) -> Option<DomRoot<Document>> { + fn document_response(&self, can_gc: CanGc) -> Option<DomRoot<Document>> { // Caching: if we have existing response xml, redirect it directly let response = self.response_xml.get(); if response.is_some() { @@ -1392,12 +1393,12 @@ impl XMLHttpRequest { } else { // TODO Step 5.2 "If charset is null, prescan the first 1024 bytes of xhr’s received bytes" // Step 5 - temp_doc = self.document_text_html(); + temp_doc = self.document_text_html(can_gc); } }, // Step 7 None => { - temp_doc = self.handle_xml(); + temp_doc = self.handle_xml(can_gc); // Not sure it the parser should throw an error for this case // The specification does not indicates this test, // but for now we check the document has no child nodes @@ -1411,7 +1412,7 @@ impl XMLHttpRequest { (mime.type_() == mime::APPLICATION && mime.subtype() == mime::XML) || mime.suffix() == Some(mime::XML) => { - temp_doc = self.handle_xml(); + temp_doc = self.handle_xml(can_gc); // Not sure it the parser should throw an error for this case // The specification does not indicates this test, // but for now we check the document has no child nodes @@ -1488,29 +1489,39 @@ impl XMLHttpRequest { self.response_json.get() } - fn document_text_html(&self) -> DomRoot<Document> { + fn document_text_html(&self, can_gc: CanGc) -> DomRoot<Document> { let charset = self.final_charset().unwrap_or(UTF_8); let wr = self.global(); let response = self.response.borrow(); let (decoded, _, _) = charset.decode(&response); - let document = self.new_doc(IsHTMLDocument::HTMLDocument); + let document = self.new_doc(IsHTMLDocument::HTMLDocument, can_gc); // TODO: Disable scripting while parsing - ServoParser::parse_html_document(&document, Some(DOMString::from(decoded)), wr.get_url()); + ServoParser::parse_html_document( + &document, + Some(DOMString::from(decoded)), + wr.get_url(), + CanGc::note(), + ); document } - fn handle_xml(&self) -> DomRoot<Document> { + fn handle_xml(&self, can_gc: CanGc) -> DomRoot<Document> { let charset = self.final_charset().unwrap_or(UTF_8); let wr = self.global(); let response = self.response.borrow(); let (decoded, _, _) = charset.decode(&response); - let document = self.new_doc(IsHTMLDocument::NonHTMLDocument); + let document = self.new_doc(IsHTMLDocument::NonHTMLDocument, can_gc); // TODO: Disable scripting while parsing - ServoParser::parse_xml_document(&document, Some(DOMString::from(decoded)), wr.get_url()); + ServoParser::parse_xml_document( + &document, + Some(DOMString::from(decoded)), + wr.get_url(), + CanGc::note(), + ); document } - fn new_doc(&self, is_html_document: IsHTMLDocument) -> DomRoot<Document> { + fn new_doc(&self, is_html_document: IsHTMLDocument, can_gc: CanGc) -> DomRoot<Document> { let wr = self.global(); let win = wr.as_window(); let doc = win.Document(); @@ -1536,6 +1547,7 @@ impl XMLHttpRequest { None, None, Default::default(), + can_gc, ) } diff --git a/components/script/microtask.rs b/components/script/microtask.rs index 820afcc5f97..086fa99cd50 100644 --- a/components/script/microtask.rs +++ b/components/script/microtask.rs @@ -23,7 +23,7 @@ use crate::dom::htmlimageelement::ImageElementMicrotask; use crate::dom::htmlmediaelement::MediaElementMicrotask; use crate::dom::mutationobserver::MutationObserver; use crate::realms::enter_realm; -use crate::script_runtime::{notify_about_rejected_promises, JSContext}; +use crate::script_runtime::{notify_about_rejected_promises, CanGc, JSContext}; use crate::script_thread::ScriptThread; /// A collection of microtasks in FIFO order. @@ -46,7 +46,7 @@ pub enum Microtask { } pub trait MicrotaskRunnable { - fn handler(&self) {} + fn handler(&self, _can_gc: CanGc) {} fn enter_realm(&self) -> JSAutoRealm; } @@ -87,6 +87,7 @@ impl MicrotaskQueue { cx: JSContext, target_provider: F, globalscopes: Vec<DomRoot<GlobalScope>>, + _can_gc: CanGc, ) where F: Fn(PipelineId) -> Option<DomRoot<GlobalScope>>, { @@ -127,14 +128,14 @@ impl MicrotaskQueue { }, Microtask::MediaElement(ref task) => { let _realm = task.enter_realm(); - task.handler(); + task.handler(CanGc::note()); }, Microtask::ImageElement(ref task) => { let _realm = task.enter_realm(); - task.handler(); + task.handler(CanGc::note()); }, Microtask::CustomElementReaction => { - ScriptThread::invoke_backup_element_queue(); + ScriptThread::invoke_backup_element_queue(CanGc::note()); }, Microtask::NotifyMutationObservers => { MutationObserver::notify_mutation_observers(); diff --git a/components/script/script_module.rs b/components/script/script_module.rs index db155fa4f00..6dfb0a64ac0 100644 --- a/components/script/script_module.rs +++ b/components/script/script_module.rs @@ -72,7 +72,7 @@ use crate::dom::window::Window; use crate::dom::worker::TrustedWorkerAddress; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; -use crate::script_runtime::JSContext as SafeJSContext; +use crate::script_runtime::{CanGc, JSContext as SafeJSContext}; use crate::task::TaskBox; use crate::task_source::TaskSourceName; @@ -1091,7 +1091,7 @@ impl FetchResponseListener for ModuleContext { if let Some(window) = global.downcast::<Window>() { window .Document() - .finish_load(LoadType::Script(self.url.clone())); + .finish_load(LoadType::Script(self.url.clone()), CanGc::note()); } // Step 9-1 & 9-2. diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 9677c371ff3..34744d73bb1 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -145,8 +145,8 @@ use crate::microtask::{Microtask, MicrotaskQueue}; use crate::realms::enter_realm; use crate::script_module::ScriptFetchOptions; use crate::script_runtime::{ - get_reports, new_rt_and_cx, CommonScriptMsg, ContextForRequestInterrupt, JSContext, Runtime, - ScriptChan, ScriptPort, ScriptThreadEventCategory, + get_reports, new_rt_and_cx, CanGc, CommonScriptMsg, ContextForRequestInterrupt, JSContext, + Runtime, ScriptChan, ScriptPort, ScriptThreadEventCategory, }; use crate::task_manager::TaskManager; use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue}; @@ -840,7 +840,7 @@ impl ScriptThreadFactory for ScriptThread { let reporter_name = format!("script-reporter-{:?}", id); mem_profiler_chan.run_with_memory_reporting( || { - script_thread.start(); + script_thread.start(CanGc::note()); let _ = script_thread.content_process_shutdown_chan.send(()); }, reporter_name, @@ -935,10 +935,11 @@ impl ScriptThread { pub fn page_headers_available( id: &PipelineId, metadata: Option<Metadata>, + can_gc: CanGc, ) -> Option<DomRoot<ServoParser>> { SCRIPT_THREAD_ROOT.with(|root| { let script_thread = unsafe { &*root.get().unwrap() }; - script_thread.handle_page_headers_available(id, metadata) + script_thread.handle_page_headers_available(id, metadata, can_gc) }) } @@ -1208,13 +1209,13 @@ impl ScriptThread { }) } - pub fn pop_current_element_queue() { + pub fn pop_current_element_queue(can_gc: CanGc) { SCRIPT_THREAD_ROOT.with(|root| { if let Some(script_thread) = root.get() { let script_thread = unsafe { &*script_thread }; script_thread .custom_element_reaction_stack - .pop_current_element_queue(); + .pop_current_element_queue(can_gc); } }) } @@ -1245,13 +1246,13 @@ impl ScriptThread { }) } - pub fn invoke_backup_element_queue() { + pub fn invoke_backup_element_queue(can_gc: CanGc) { SCRIPT_THREAD_ROOT.with(|root| { if let Some(script_thread) = root.get() { let script_thread = unsafe { &*script_thread }; script_thread .custom_element_reaction_stack - .invoke_backup_element_queue(); + .invoke_backup_element_queue(can_gc); } }) } @@ -1447,9 +1448,9 @@ impl ScriptThread { /// Starts the script thread. After calling this method, the script thread will loop receiving /// messages on its port. - pub fn start(&self) { + pub fn start(&self, _can_gc: CanGc) { debug!("Starting script thread."); - while self.handle_msgs() { + while self.handle_msgs(CanGc::note()) { // Go on... debug!("Running script thread."); } @@ -1781,7 +1782,7 @@ impl ScriptThread { } /// Handle incoming messages from other tasks and the task queue. - fn handle_msgs(&self) -> bool { + fn handle_msgs(&self, _can_gc: CanGc) -> bool { use self::MixedMessage::{ FromConstellation, FromDevtools, FromImageCache, FromScript, FromWebGPUServer, }; @@ -1893,7 +1894,7 @@ impl ScriptThread { // Run the "update the rendering" task. task.run_box(); // Always perform a microtrask checkpoint after running a task. - self.perform_a_microtask_checkpoint(); + self.perform_a_microtask_checkpoint(CanGc::note()); }, FromScript(MainThreadScriptMsg::Inactive) => { // An event came-in from a document that is not fully-active, it has been stored by the task-queue. @@ -1948,14 +1949,18 @@ impl ScriptThread { // If we've received the closed signal from the BHM, only handle exit messages. match msg { FromConstellation(ConstellationControlMsg::ExitScriptThread) => { - self.handle_exit_script_thread_msg(); + self.handle_exit_script_thread_msg(CanGc::note()); return false; }, FromConstellation(ConstellationControlMsg::ExitPipeline( pipeline_id, discard_browsing_context, )) => { - self.handle_exit_pipeline_msg(pipeline_id, discard_browsing_context); + self.handle_exit_pipeline_msg( + pipeline_id, + discard_browsing_context, + CanGc::note(), + ); }, _ => {}, } @@ -1965,10 +1970,12 @@ impl ScriptThread { let result = self.profile_event(category, pipeline_id, move || { match msg { FromConstellation(ConstellationControlMsg::ExitScriptThread) => { - self.handle_exit_script_thread_msg(); + self.handle_exit_script_thread_msg(CanGc::note()); return Some(false); }, - FromConstellation(inner_msg) => self.handle_msg_from_constellation(inner_msg), + FromConstellation(inner_msg) => { + self.handle_msg_from_constellation(inner_msg, CanGc::note()) + }, FromScript(inner_msg) => self.handle_msg_from_script(inner_msg), FromDevtools(inner_msg) => self.handle_msg_from_devtools(inner_msg), FromImageCache(inner_msg) => self.handle_msg_from_image_cache(inner_msg), @@ -1984,7 +1991,7 @@ impl ScriptThread { // https://html.spec.whatwg.org/multipage/#event-loop-processing-model step 6 // TODO(#32003): A microtask checkpoint is only supposed to be performed after running a task. - self.perform_a_microtask_checkpoint(); + self.perform_a_microtask_checkpoint(CanGc::note()); } { @@ -2246,7 +2253,7 @@ impl ScriptThread { value } - fn handle_msg_from_constellation(&self, msg: ConstellationControlMsg) { + fn handle_msg_from_constellation(&self, msg: ConstellationControlMsg, can_gc: CanGc) { match msg { ConstellationControlMsg::StopDelayingLoadEventsMode(pipeline_id) => { self.handle_stop_delaying_load_events_mode(pipeline_id) @@ -2273,6 +2280,7 @@ impl ScriptThread { browsing_context_id, load_data, replace, + can_gc, ), ConstellationControlMsg::UnloadDocument(pipeline_id) => { self.handle_unload_document(pipeline_id) @@ -2325,6 +2333,7 @@ impl ScriptThread { top_level_browsing_context_id, new_pipeline_id, reason, + can_gc, ), ConstellationControlMsg::UpdateHistoryState(pipeline_id, history_state_id, url) => { self.handle_update_history_state_msg(pipeline_id, history_state_id, url) @@ -2345,7 +2354,7 @@ impl ScriptThread { target: browsing_context_id, parent: parent_id, child: child_id, - } => self.handle_iframe_load_event(parent_id, browsing_context_id, child_id), + } => self.handle_iframe_load_event(parent_id, browsing_context_id, child_id, can_gc), ConstellationControlMsg::DispatchStorageEvent( pipeline_id, storage, @@ -2359,13 +2368,13 @@ impl ScriptThread { }, ConstellationControlMsg::Reload(pipeline_id) => self.handle_reload(pipeline_id), ConstellationControlMsg::ExitPipeline(pipeline_id, discard_browsing_context) => { - self.handle_exit_pipeline_msg(pipeline_id, discard_browsing_context) + self.handle_exit_pipeline_msg(pipeline_id, discard_browsing_context, can_gc) }, ConstellationControlMsg::PaintMetric(pipeline_id, metric_type, metric_value) => { self.handle_paint_metric(pipeline_id, metric_type, metric_value) }, ConstellationControlMsg::MediaSessionAction(pipeline_id, action) => { - self.handle_media_session_action(pipeline_id, action) + self.handle_media_session_action(pipeline_id, action, can_gc) }, ConstellationControlMsg::SetWebGPUPort(port) => { if self.webgpu_port.borrow().is_some() { @@ -3050,13 +3059,14 @@ impl ScriptThread { top_level_browsing_context_id: TopLevelBrowsingContextId, new_pipeline_id: PipelineId, reason: UpdatePipelineIdReason, + can_gc: CanGc, ) { let frame_element = self .documents .borrow() .find_iframe(parent_pipeline_id, browsing_context_id); if let Some(frame_element) = frame_element { - frame_element.update_pipeline_id(new_pipeline_id, reason); + frame_element.update_pipeline_id(new_pipeline_id, reason, can_gc); } if let Some(window) = self.documents.borrow().find_window(new_pipeline_id) { @@ -3123,6 +3133,7 @@ impl ScriptThread { &self, id: &PipelineId, metadata: Option<Metadata>, + _can_gc: CanGc, ) -> Option<DomRoot<ServoParser>> { let idx = self .incomplete_loads @@ -3161,7 +3172,7 @@ impl ScriptThread { }; let load = self.incomplete_loads.borrow_mut().remove(idx); - metadata.map(|meta| self.load(meta, load)) + metadata.map(|meta| self.load(meta, load, CanGc::note())) }, None => { assert!(self.closed_pipelines.borrow().contains(id)); @@ -3244,7 +3255,12 @@ impl ScriptThread { } /// Handles a request to exit a pipeline and shut down layout. - fn handle_exit_pipeline_msg(&self, id: PipelineId, discard_bc: DiscardBrowsingContext) { + fn handle_exit_pipeline_msg( + &self, + id: PipelineId, + discard_bc: DiscardBrowsingContext, + can_gc: CanGc, + ) { debug!("{id}: Starting pipeline exit."); self.closed_pipelines.borrow_mut().insert(id); @@ -3261,7 +3277,7 @@ impl ScriptThread { .any(|load| load.pipeline_id == id)); if let Some(parser) = document.get_current_parser() { - parser.abort(); + parser.abort(can_gc); } debug!("{id}: Shutting down layout"); @@ -3298,7 +3314,7 @@ impl ScriptThread { } /// Handles a request to exit the script thread and shut down layout. - fn handle_exit_script_thread_msg(&self) { + fn handle_exit_script_thread_msg(&self, _can_gc: CanGc) { debug!("Exiting script thread."); let mut pipeline_ids = Vec::new(); @@ -3318,7 +3334,7 @@ impl ScriptThread { ); for pipeline_id in pipeline_ids { - self.handle_exit_pipeline_msg(pipeline_id, DiscardBrowsingContext::Yes); + self.handle_exit_pipeline_msg(pipeline_id, DiscardBrowsingContext::Yes, CanGc::note()); } self.background_hang_monitor.unregister(); @@ -3399,13 +3415,14 @@ impl ScriptThread { parent_id: PipelineId, browsing_context_id: BrowsingContextId, child_id: PipelineId, + can_gc: CanGc, ) { let iframe = self .documents .borrow() .find_iframe(parent_id, browsing_context_id); match iframe { - Some(iframe) => iframe.iframe_load_event_steps(child_id), + Some(iframe) => iframe.iframe_load_event_steps(child_id, can_gc), None => warn!("Message sent to closed pipeline {}.", parent_id), } } @@ -3547,7 +3564,12 @@ impl ScriptThread { /// The entry point to document loading. Defines bindings, sets up the window and document /// objects, parses HTML and CSS, and kicks off initial layout. - fn load(&self, metadata: Metadata, incomplete: InProgressLoad) -> DomRoot<ServoParser> { + fn load( + &self, + metadata: Metadata, + incomplete: InProgressLoad, + can_gc: CanGc, + ) -> DomRoot<ServoParser> { let final_url = metadata.final_url.clone(); { self.script_sender @@ -3736,6 +3758,7 @@ impl ScriptThread { referrer_policy, Some(status_code), incomplete.canceller, + CanGc::note(), ); document.set_ready_state(DocumentReadyState::Loading); @@ -3758,6 +3781,7 @@ impl ScriptThread { window_proxy.top_level_browsing_context_id(), incomplete.pipeline_id, UpdatePipelineIdReason::Navigation, + can_gc, ); } @@ -3776,9 +3800,9 @@ impl ScriptThread { document.set_navigation_start(incomplete.navigation_start); if is_html_document == IsHTMLDocument::NonHTMLDocument { - ServoParser::parse_xml_document(&document, None, final_url); + ServoParser::parse_xml_document(&document, None, final_url, CanGc::note()); } else { - ServoParser::parse_html_document(&document, None, final_url); + ServoParser::parse_html_document(&document, None, final_url, CanGc::note()); } if incomplete.activity == DocumentActivity::FullyActive { @@ -3901,13 +3925,14 @@ impl ScriptThread { browsing_context_id: BrowsingContextId, load_data: LoadData, replace: HistoryEntryReplacement, + can_gc: CanGc, ) { let iframe = self .documents .borrow() .find_iframe(parent_pipeline_id, browsing_context_id); if let Some(iframe) = iframe { - iframe.navigate_or_reload_child_browsing_context(load_data, replace); + iframe.navigate_or_reload_child_browsing_context(load_data, replace, can_gc); } } @@ -4179,10 +4204,15 @@ impl ScriptThread { } } - fn handle_media_session_action(&self, pipeline_id: PipelineId, action: MediaSessionActionType) { + fn handle_media_session_action( + &self, + pipeline_id: PipelineId, + action: MediaSessionActionType, + can_gc: CanGc, + ) { if let Some(window) = self.documents.borrow().find_window(pipeline_id) { let media_session = window.Navigator().MediaSession(); - media_session.handle_action(action); + media_session.handle_action(action, can_gc); } else { warn!("No MediaSession for this pipeline ID"); }; @@ -4197,7 +4227,7 @@ impl ScriptThread { }); } - fn perform_a_microtask_checkpoint(&self) { + fn perform_a_microtask_checkpoint(&self, can_gc: CanGc) { // Only perform the checkpoint if we're not shutting down. if self.can_continue_running_inner() { let globals = self @@ -4211,6 +4241,7 @@ impl ScriptThread { self.get_cx(), |id| self.documents.borrow().find_global(id), globals, + can_gc, ) } } diff --git a/components/script/serviceworker_manager.rs b/components/script/serviceworker_manager.rs index 8059e4ee41b..1c377bfc8a1 100644 --- a/components/script/serviceworker_manager.rs +++ b/components/script/serviceworker_manager.rs @@ -29,7 +29,7 @@ use crate::dom::serviceworkerglobalscope::{ ServiceWorkerControlMsg, ServiceWorkerGlobalScope, ServiceWorkerScriptMsg, }; use crate::dom::serviceworkerregistration::longest_prefix_match; -use crate::script_runtime::ContextForRequestInterrupt; +use crate::script_runtime::{CanGc, ContextForRequestInterrupt}; enum Message { FromResource(CustomResponseMediator), @@ -250,10 +250,12 @@ impl ServiceWorkerManager { None } - fn handle_message(&mut self) { + fn handle_message(&mut self, _can_gc: CanGc) { while let Ok(message) = self.receive_message() { let should_continue = match message { - Message::FromConstellation(msg) => self.handle_message_from_constellation(msg), + Message::FromConstellation(msg) => { + self.handle_message_from_constellation(msg, CanGc::note()) + }, Message::FromResource(msg) => self.handle_message_from_resource(msg), }; if !should_continue { @@ -288,7 +290,7 @@ impl ServiceWorkerManager { } } - fn handle_message_from_constellation(&mut self, msg: ServiceWorkerMsg) -> bool { + fn handle_message_from_constellation(&mut self, msg: ServiceWorkerMsg, can_gc: CanGc) -> bool { match msg { ServiceWorkerMsg::Timeout(_scope) => { // TODO: https://w3c.github.io/ServiceWorker/#terminate-service-worker @@ -305,7 +307,7 @@ impl ServiceWorkerManager { self.handle_register_job(job); }, JobType::Update => { - self.handle_update_job(job); + self.handle_update_job(job, can_gc); }, JobType::Unregister => { // TODO: https://w3c.github.io/ServiceWorker/#unregister-algorithm @@ -380,7 +382,7 @@ impl ServiceWorkerManager { } /// <https://w3c.github.io/ServiceWorker/#update> - fn handle_update_job(&mut self, job: Job) { + fn handle_update_job(&mut self, job: Job, can_gc: CanGc) { // Step 1: Get registation if let Some(registration) = self.registrations.get_mut(&job.scope_url) { // Step 3. @@ -403,8 +405,12 @@ impl ServiceWorkerManager { // Very roughly steps 5 to 18. // TODO: implement all steps precisely. - let (new_worker, join_handle, control_sender, context, closing) = - update_serviceworker(self.own_sender.clone(), job.scope_url.clone(), scope_things); + let (new_worker, join_handle, control_sender, context, closing) = update_serviceworker( + self.own_sender.clone(), + job.scope_url.clone(), + scope_things, + can_gc, + ); // Since we've just started the worker thread, ensure we can shut it down later. registration.note_worker_thread(join_handle, control_sender, context, closing); @@ -443,6 +449,7 @@ fn update_serviceworker( own_sender: IpcSender<ServiceWorkerMsg>, scope_url: ServoUrl, scope_things: ScopeThings, + can_gc: CanGc, ) -> ( ServiceWorker, JoinHandle<()>, @@ -468,6 +475,7 @@ fn update_serviceworker( control_receiver, context_sender, closing.clone(), + can_gc, ); let context = context_receiver @@ -504,7 +512,7 @@ impl ServiceWorkerManagerFactory for ServiceWorkerManager { resource_port, constellation_sender, ) - .handle_message() + .handle_message(CanGc::note()) }; if thread::Builder::new() .name("SvcWorkerManager".to_owned()) diff --git a/components/script/stylesheet_loader.rs b/components/script/stylesheet_loader.rs index 90aeb8754f1..079566d1971 100644 --- a/components/script/stylesheet_loader.rs +++ b/components/script/stylesheet_loader.rs @@ -44,6 +44,7 @@ use crate::dom::performanceresourcetiming::InitiatorType; use crate::dom::shadowroot::ShadowRoot; use crate::fetch::create_a_potential_cors_request; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; +use crate::script_runtime::CanGc; pub trait StylesheetOwner { /// Returns whether this element was inserted by the parser (i.e., it should @@ -213,7 +214,7 @@ impl FetchResponseListener for StylesheetContext { document.decrement_script_blocking_stylesheet_count(); } - document.finish_load(LoadType::Stylesheet(self.url.clone())); + document.finish_load(LoadType::Stylesheet(self.url.clone()), CanGc::note()); if let Some(any_failed) = owner.load_finished(successful) { let event = if any_failed { |