Propagate CanGc from Document::new() (#33386)

* Add canGc as a parameter to autogenerated trait methods

Signed-off-by: Andriy Sultanov <sultanovandriy@gmail.com>

* Propagate CanGc from Document::new()

Signed-off-by: Andriy Sultanov <sultanovandriy@gmail.com>

---------

Signed-off-by: Andriy Sultanov <sultanovandriy@gmail.com>
This commit is contained in:
Andriy Sultanov 2024-09-09 23:38:01 +01:00 committed by GitHub
parent 10e5bb72d9
commit e5150dbda1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
41 changed files with 704 additions and 393 deletions

View file

@ -14,6 +14,7 @@ use servo_url::ServoUrl;
use crate::dom::bindings::root::Dom; use crate::dom::bindings::root::Dom;
use crate::dom::document::Document; use crate::dom::document::Document;
use crate::fetch::FetchCanceller; use crate::fetch::FetchCanceller;
use crate::script_runtime::CanGc;
#[derive(Clone, Debug, JSTraceable, MallocSizeOf, PartialEq)] #[derive(Clone, Debug, JSTraceable, MallocSizeOf, PartialEq)]
pub enum LoadType { pub enum LoadType {
@ -48,9 +49,9 @@ impl LoadBlocker {
} }
/// Remove this load from the associated document's list of blocking loads. /// 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() { 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; *blocker = None;
} }
@ -59,7 +60,7 @@ impl LoadBlocker {
impl Drop for LoadBlocker { impl Drop for LoadBlocker {
fn drop(&mut self) { fn drop(&mut self) {
if let Some(load) = self.load.take() { if let Some(load) = self.load.take() {
self.doc.finish_load(load); self.doc.finish_load(load, CanGc::note());
} }
} }
} }

View file

@ -13,7 +13,7 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::worker::TrustedWorkerAddress; use crate::dom::worker::TrustedWorkerAddress;
use crate::dom::workerglobalscope::WorkerGlobalScope; use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::realms::enter_realm; 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}; use crate::task_queue::{QueuedTaskConversion, TaskQueue};
/// A ScriptChan that can be cloned freely and will silently send a TrustedWorkerAddress with /// 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>( pub fn run_worker_event_loop<T, WorkerMsg, Event>(
worker_scope: &T, worker_scope: &T,
worker: Option<&TrustedWorkerAddress>, worker: Option<&TrustedWorkerAddress>,
_can_gc: CanGc,
) where ) where
WorkerMsg: QueuedTaskConversion + Send, WorkerMsg: QueuedTaskConversion + Send,
T: WorkerEventLoopMethods<WorkerMsg = WorkerMsg, Event = Event> T: WorkerEventLoopMethods<WorkerMsg = WorkerMsg, Event = Event>
@ -155,7 +156,7 @@ pub fn run_worker_event_loop<T, WorkerMsg, Event>(
}; };
worker_scope worker_scope
.upcast::<GlobalScope>() .upcast::<GlobalScope>()
.perform_a_microtask_checkpoint(); .perform_a_microtask_checkpoint(CanGc::note());
} }
worker_scope worker_scope
.upcast::<GlobalScope>() .upcast::<GlobalScope>()

View file

@ -40,6 +40,7 @@ DOMInterfaces = {
'Range': { 'Range': {
'weakReferenceable': True, 'weakReferenceable': True,
'canGc': ['CreateContextualFragment', 'ExtractContents', 'CloneContents', 'CloneRange', 'SurroundContents'],
}, },
'EventSource': { 'EventSource': {
@ -70,6 +71,7 @@ DOMInterfaces = {
'Window': { 'Window': {
'inRealms': ['Fetch', 'GetOpener'], 'inRealms': ['Fetch', 'GetOpener'],
'canGc': ['Stop'],
}, },
'WorkerGlobalScope': { 'WorkerGlobalScope': {
@ -90,6 +92,7 @@ DOMInterfaces = {
'HTMLMediaElement': { 'HTMLMediaElement': {
'inRealms': ['Play'], 'inRealms': ['Play'],
'canGc': ['Play', 'Pause', 'Load', 'SetSrcObject'],
}, },
'BluetoothRemoteGATTDescriptor': { 'BluetoothRemoteGATTDescriptor': {
@ -180,6 +183,39 @@ DOMInterfaces = {
'GamepadHapticActuator': { 'GamepadHapticActuator': {
'inRealms': ['PlayEffect', 'Reset'] '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'],
},
} }

View file

@ -3700,6 +3700,8 @@ class CGCallGenerator(CGThing):
args.prepend(CGGeneric("cx")) args.prepend(CGGeneric("cx"))
if nativeMethodName in descriptor.inRealmMethods: if nativeMethodName in descriptor.inRealmMethods:
args.append(CGGeneric("InRealm::already(&AlreadyInRealm::assert_for_cx(cx))")) 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 # Build up our actual call
self.cgRoot = CGList([], "\n") self.cgRoot = CGList([], "\n")
@ -3723,7 +3725,7 @@ class CGCallGenerator(CGThing):
])) ]))
if hasCEReactions: 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 isFallible:
if static: if static:
@ -6263,7 +6265,7 @@ class CGInterfaceTrait(CGThing):
def __init__(self, descriptor): def __init__(self, descriptor):
CGThing.__init__(self) CGThing.__init__(self)
def attribute_arguments(needCx, argument=None, inRealm=False): def attribute_arguments(needCx, argument=None, inRealm=False, canGc=False):
if needCx: if needCx:
yield "cx", "SafeJSContext" yield "cx", "SafeJSContext"
@ -6273,6 +6275,9 @@ class CGInterfaceTrait(CGThing):
if inRealm: if inRealm:
yield "_comp", "InRealm" yield "_comp", "InRealm"
if canGc:
yield "_can_gc", "CanGc"
def members(): def members():
for m in descriptor.interface.members: for m in descriptor.interface.members:
if (m.isMethod() and not m.isStatic() if (m.isMethod() and not m.isStatic()
@ -6283,7 +6288,8 @@ class CGInterfaceTrait(CGThing):
infallible = 'infallible' in descriptor.getExtendedAttributes(m) infallible = 'infallible' in descriptor.getExtendedAttributes(m)
for idx, (rettype, arguments) in enumerate(m.signatures()): for idx, (rettype, arguments) in enumerate(m.signatures()):
arguments = method_arguments(descriptor, rettype, arguments, 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) rettype = return_type(descriptor, rettype, infallible)
yield f"{name}{'_' * idx}", arguments, rettype yield f"{name}{'_' * idx}", arguments, rettype
elif m.isAttr() and not m.isStatic(): elif m.isAttr() and not m.isStatic():
@ -6292,7 +6298,8 @@ class CGInterfaceTrait(CGThing):
yield (name, yield (name,
attribute_arguments( attribute_arguments(
typeNeedsCx(m.type, True), 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)) return_type(descriptor, m.type, infallible))
@ -6307,7 +6314,8 @@ class CGInterfaceTrait(CGThing):
attribute_arguments( attribute_arguments(
typeNeedsCx(m.type, False), typeNeedsCx(m.type, False),
m.type, m.type,
inRealm=name in descriptor.inRealmMethods inRealm=name in descriptor.inRealmMethods,
canGc=name in descriptor.canGcMethods
), ),
rettype) rettype)
@ -6324,7 +6332,8 @@ class CGInterfaceTrait(CGThing):
if not rettype.nullable(): if not rettype.nullable():
rettype = IDLNullableType(rettype.location, rettype) rettype = IDLNullableType(rettype.location, rettype)
arguments = method_arguments(descriptor, rettype, arguments, 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 # If this interface 'supports named properties', then we
# should be able to access 'supported property names' # should be able to access 'supported property names'
@ -6335,7 +6344,8 @@ class CGInterfaceTrait(CGThing):
yield "SupportedPropertyNames", [], "Vec<DOMString>" yield "SupportedPropertyNames", [], "Vec<DOMString>"
else: else:
arguments = method_arguments(descriptor, rettype, arguments, 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) rettype = return_type(descriptor, rettype, infallible)
yield name, arguments, rettype yield name, arguments, rettype
@ -7123,7 +7133,8 @@ def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, var
return declType.define() 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): if needCx(returnType, arguments, passJSBits):
yield "cx", "SafeJSContext" yield "cx", "SafeJSContext"
@ -7138,6 +7149,9 @@ def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True,
if inRealm: if inRealm:
yield "_comp", "InRealm" yield "_comp", "InRealm"
if canGc:
yield "_can_gc", "CanGc"
def return_type(descriptorProvider, rettype, infallible): def return_type(descriptorProvider, rettype, infallible):
result = getRetvalDeclarationForType(rettype, descriptorProvider) result = getRetvalDeclarationForType(rettype, descriptorProvider)

View file

@ -232,6 +232,7 @@ class Descriptor(DescriptorProvider):
self.register = desc.get('register', True) self.register = desc.get('register', True)
self.path = desc.get('path', pathDefault) self.path = desc.get('path', pathDefault)
self.inRealmMethods = [name for name in desc.get('inRealms', [])] 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.bindingPath = f"{getModuleFromObject(self.interface)}::{ifaceName}_Binding"
self.outerObjectHook = desc.get('outerObjectHook', 'None') self.outerObjectHook = desc.get('outerObjectHook', 'None')
self.proxy = False self.proxy = False

View file

@ -51,7 +51,7 @@ use crate::dom::element::{Element, ElementCreator};
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlelement::HTMLElement;
use crate::dom::window::Window; 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; use crate::script_thread::ScriptThread;
// https://html.spec.whatwg.org/multipage/#htmlconstructor // 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() { pub fn pop_current_element_queue(can_gc: CanGc) {
ScriptThread::pop_current_element_queue(); ScriptThread::pop_current_element_queue(can_gc);
} }
pub fn push_new_element_queue() { pub fn push_new_element_queue() {

View file

@ -11,6 +11,7 @@ use js::rust::Runtime;
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::trace::JSTraceable; use crate::dom::bindings::trace::JSTraceable;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::script_runtime::CanGc;
thread_local!(static STACK: RefCell<Vec<StackEntry>> = const { RefCell::new(Vec::new()) }); thread_local!(static STACK: RefCell<Vec<StackEntry>> = const { RefCell::new(Vec::new()) });
@ -76,7 +77,7 @@ impl Drop for AutoEntryScript {
// Step 5 // Step 5
if !thread::panicking() && incumbent_global().is_none() { if !thread::panicking() && incumbent_global().is_none() {
self.global.perform_a_microtask_checkpoint(); self.global.perform_a_microtask_checkpoint(CanGc::note());
} }
} }
} }

View file

@ -86,6 +86,7 @@ use crate::dom::htmlvideoelement::HTMLVideoElement;
use crate::dom::svgelement::SVGElement; use crate::dom::svgelement::SVGElement;
use crate::dom::svgsvgelement::SVGSVGElement; use crate::dom::svgsvgelement::SVGSVGElement;
use crate::realms::{enter_realm, InRealm}; use crate::realms::{enter_realm, InRealm};
use crate::script_runtime::CanGc;
use crate::script_thread::ScriptThread; use crate::script_thread::ScriptThread;
fn create_svg_element( fn create_svg_element(
@ -127,6 +128,7 @@ fn create_html_element(
creator: ElementCreator, creator: ElementCreator,
mode: CustomElementCreationMode, mode: CustomElementCreationMode,
proto: Option<HandleObject>, proto: Option<HandleObject>,
can_gc: CanGc,
) -> DomRoot<Element> { ) -> DomRoot<Element> {
assert_eq!(name.ns, ns!(html)); assert_eq!(name.ns, ns!(html));
@ -150,7 +152,7 @@ fn create_html_element(
CustomElementCreationMode::Synchronous => { CustomElementCreationMode::Synchronous => {
let local_name = name.local.clone(); let local_name = name.local.clone();
//TODO(jdm) Pass proto to create_element? //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) => { Ok(element) => {
element.set_custom_element_definition(definition.clone()); element.set_custom_element_definition(definition.clone());
element element
@ -185,7 +187,9 @@ fn create_html_element(
element.set_custom_element_state(CustomElementState::Undefined); element.set_custom_element_state(CustomElementState::Undefined);
match mode { match mode {
// Step 5.3 // Step 5.3
CustomElementCreationMode::Synchronous => upgrade_element(definition, &element), CustomElementCreationMode::Synchronous => {
upgrade_element(definition, &element, can_gc)
},
// Step 5.4 // Step 5.4
CustomElementCreationMode::Asynchronous => { CustomElementCreationMode::Asynchronous => {
ScriptThread::enqueue_upgrade_reaction(&element, definition) ScriptThread::enqueue_upgrade_reaction(&element, definition)
@ -395,10 +399,11 @@ pub fn create_element(
creator: ElementCreator, creator: ElementCreator,
mode: CustomElementCreationMode, mode: CustomElementCreationMode,
proto: Option<HandleObject>, proto: Option<HandleObject>,
can_gc: CanGc,
) -> DomRoot<Element> { ) -> DomRoot<Element> {
let prefix = name.prefix.clone(); let prefix = name.prefix.clone();
match name.ns { 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), ns!(svg) => create_svg_element(name, prefix, document, proto),
_ => Element::new(name.local, name.ns, prefix, document, proto), _ => Element::new(name.local, name.ns, prefix, document, proto),
} }

View file

@ -48,7 +48,7 @@ use crate::dom::promise::Promise;
use crate::dom::window::Window; use crate::dom::window::Window;
use crate::microtask::Microtask; use crate::microtask::Microtask;
use crate::realms::{enter_realm, InRealm}; use crate::realms::{enter_realm, InRealm};
use crate::script_runtime::JSContext; use crate::script_runtime::{CanGc, JSContext};
use crate::script_thread::ScriptThread; use crate::script_thread::ScriptThread;
/// <https://dom.spec.whatwg.org/#concept-element-custom-element-state> /// <https://dom.spec.whatwg.org/#concept-element-custom-element-state>
@ -718,6 +718,7 @@ impl CustomElementDefinition {
&self, &self,
document: &Document, document: &Document,
prefix: Option<Prefix>, prefix: Option<Prefix>,
can_gc: CanGc,
) -> Fallible<DomRoot<Element>> { ) -> Fallible<DomRoot<Element>> {
let window = document.window(); let window = document.window();
let cx = GlobalScope::get_cx(); let cx = GlobalScope::get_cx();
@ -738,7 +739,7 @@ impl CustomElementDefinition {
if is_execution_stack_empty() { if is_execution_stack_empty() {
window window
.upcast::<GlobalScope>() .upcast::<GlobalScope>()
.perform_a_microtask_checkpoint(); .perform_a_microtask_checkpoint(can_gc);
} }
rooted!(in(*cx) let element_val = ObjectValue(element.get())); 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> /// <https://html.spec.whatwg.org/multipage/#concept-upgrade-an-element>
#[allow(unsafe_code)] #[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 // Step 1
let state = element.get_custom_element_state(); let state = element.get_custom_element_state();
if state != CustomElementState::Undefined && state != CustomElementState::Uncustomized { 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))); .push(ConstructionStackEntry::Element(DomRoot::from_ref(element)));
// Steps 7-8, successful case // 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 // "regardless of whether the above steps threw an exception" step
definition.construction_stack.borrow_mut().pop(); definition.construction_stack.borrow_mut().pop();
@ -897,6 +898,7 @@ pub fn upgrade_element(definition: Rc<CustomElementDefinition>, element: &Elemen
fn run_upgrade_constructor( fn run_upgrade_constructor(
constructor: &Rc<CustomElementConstructor>, constructor: &Rc<CustomElementConstructor>,
element: &Element, element: &Element,
can_gc: CanGc,
) -> ErrorResult { ) -> ErrorResult {
let window = window_from_node(element); let window = window_from_node(element);
let cx = GlobalScope::get_cx(); let cx = GlobalScope::get_cx();
@ -929,7 +931,7 @@ fn run_upgrade_constructor(
if is_execution_stack_empty() { if is_execution_stack_empty() {
window window
.upcast::<GlobalScope>() .upcast::<GlobalScope>()
.perform_a_microtask_checkpoint(); .perform_a_microtask_checkpoint(can_gc);
} }
// Step 8.3 // Step 8.3
@ -982,11 +984,11 @@ pub enum CustomElementReaction {
impl CustomElementReaction { impl CustomElementReaction {
/// <https://html.spec.whatwg.org/multipage/#invoke-custom-element-reactions> /// <https://html.spec.whatwg.org/multipage/#invoke-custom-element-reactions>
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub fn invoke(&self, element: &Element) { pub fn invoke(&self, element: &Element, can_gc: CanGc) {
// Step 2.1 // Step 2.1
match *self { match *self {
CustomElementReaction::Upgrade(ref definition) => { CustomElementReaction::Upgrade(ref definition) => {
upgrade_element(definition.clone(), element) upgrade_element(definition.clone(), element, can_gc)
}, },
CustomElementReaction::Callback(ref callback, ref arguments) => { CustomElementReaction::Callback(ref callback, ref arguments) => {
// We're rooted, so it's safe to hand out a handle to objects in Heap // 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()); 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); rooted_vec!(let mut stack);
mem::swap(&mut *stack, &mut *self.stack.borrow_mut()); mem::swap(&mut *stack, &mut *self.stack.borrow_mut());
if let Some(current_queue) = stack.last() { if let Some(current_queue) = stack.last() {
current_queue.invoke_reactions(); current_queue.invoke_reactions(can_gc);
} }
stack.pop(); stack.pop();
@ -1054,9 +1056,9 @@ impl CustomElementReactionStack {
/// <https://html.spec.whatwg.org/multipage/#enqueue-an-element-on-the-appropriate-element-queue> /// <https://html.spec.whatwg.org/multipage/#enqueue-an-element-on-the-appropriate-element-queue>
/// Step 4 /// Step 4
pub fn invoke_backup_element_queue(&self) { pub fn invoke_backup_element_queue(&self, can_gc: CanGc) {
// Step 4.1 // Step 4.1
self.backup_queue.invoke_reactions(); self.backup_queue.invoke_reactions(can_gc);
// Step 4.2 // Step 4.2
self.processing_backup_element_queue self.processing_backup_element_queue
@ -1237,10 +1239,10 @@ impl ElementQueue {
} }
/// <https://html.spec.whatwg.org/multipage/#invoke-custom-element-reactions> /// <https://html.spec.whatwg.org/multipage/#invoke-custom-element-reactions>
fn invoke_reactions(&self) { fn invoke_reactions(&self, _can_gc: CanGc) {
// Steps 1-2 // Steps 1-2
while let Some(element) = self.next_element() { while let Some(element) = self.next_element() {
element.invoke_reactions() element.invoke_reactions(CanGc::note())
} }
self.queue.borrow_mut().clear(); self.queue.borrow_mut().clear();
} }

View file

@ -55,8 +55,8 @@ use crate::fetch::load_whole_resource;
use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; use crate::realms::{enter_realm, AlreadyInRealm, InRealm};
use crate::script_runtime::ScriptThreadEventCategory::WorkerEvent; use crate::script_runtime::ScriptThreadEventCategory::WorkerEvent;
use crate::script_runtime::{ use crate::script_runtime::{
new_child_runtime, CommonScriptMsg, ContextForRequestInterrupt, JSContext as SafeJSContext, new_child_runtime, CanGc, CommonScriptMsg, ContextForRequestInterrupt,
Runtime, ScriptChan, ScriptPort, JSContext as SafeJSContext, Runtime, ScriptChan, ScriptPort,
}; };
use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue}; use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
use crate::task_source::networking::NetworkingTaskSource; use crate::task_source::networking::NetworkingTaskSource;
@ -333,6 +333,7 @@ impl DedicatedWorkerGlobalScope {
gpu_id_hub: Arc<Identities>, gpu_id_hub: Arc<Identities>,
control_receiver: Receiver<DedicatedWorkerControlMsg>, control_receiver: Receiver<DedicatedWorkerControlMsg>,
context_sender: Sender<ContextForRequestInterrupt>, context_sender: Sender<ContextForRequestInterrupt>,
_can_gc: CanGc,
) -> JoinHandle<()> { ) -> JoinHandle<()> {
let serialized_worker_url = worker_url.to_string(); let serialized_worker_url = worker_url.to_string();
let top_level_browsing_context_id = TopLevelBrowsingContextId::installed(); let top_level_browsing_context_id = TopLevelBrowsingContextId::installed();
@ -478,7 +479,7 @@ impl DedicatedWorkerGlobalScope {
// until the event loop is destroyed, // until the event loop is destroyed,
// which happens after the closing flag is set to true. // which happens after the closing flag is set to true.
while !scope.is_closing() { while !scope.is_closing() {
run_worker_event_loop(&*global, Some(&worker)); run_worker_event_loop(&*global, Some(&worker), CanGc::note());
} }
}, },
reporter_name, reporter_name,

View file

@ -2117,7 +2117,7 @@ impl Document {
// https://html.spec.whatwg.org/multipage/#the-end // https://html.spec.whatwg.org/multipage/#the-end
// https://html.spec.whatwg.org/multipage/#delay-the-load-event // 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. // This does not delay the load event anymore.
debug!("Document got finish_load: {:?}", load); debug!("Document got finish_load: {:?}", load);
self.loader.borrow_mut().finish_load(&load); self.loader.borrow_mut().finish_load(&load);
@ -2126,7 +2126,7 @@ impl Document {
LoadType::Stylesheet(_) => { LoadType::Stylesheet(_) => {
// A stylesheet finishing to load may unblock any pending // A stylesheet finishing to load may unblock any pending
// parsing-blocking script or deferred script. // parsing-blocking script or deferred script.
self.process_pending_parsing_blocking_script(); self.process_pending_parsing_blocking_script(can_gc);
// Step 3. // Step 3.
self.process_deferred_scripts(); self.process_deferred_scripts();
@ -2489,6 +2489,7 @@ impl Document {
&self, &self,
element: &HTMLScriptElement, element: &HTMLScriptElement,
result: ScriptResult, result: ScriptResult,
can_gc: CanGc,
) { ) {
{ {
let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut(); let mut blocking_script = self.pending_parsing_blocking_script.borrow_mut();
@ -2496,10 +2497,10 @@ impl Document {
assert!(&*entry.element == element); assert!(&*entry.element == element);
entry.loaded(result); 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 { if self.script_blocking_stylesheets_count.get() > 0 {
return; return;
} }
@ -2512,7 +2513,7 @@ impl Document {
*self.pending_parsing_blocking_script.borrow_mut() = None; *self.pending_parsing_blocking_script.borrow_mut() = None;
self.get_current_parser() self.get_current_parser()
.unwrap() .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 // 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. // We need to inhibit the loader before anything else.
self.loader.borrow_mut().inhibit_events(); self.loader.borrow_mut().inhibit_events();
@ -2637,7 +2638,7 @@ impl Document {
for iframe in self.iter_iframes() { for iframe in self.iter_iframes() {
if let Some(document) = iframe.GetContentDocument() { if let Some(document) = iframe.GetContentDocument() {
// TODO: abort the active documents of every child browsing context. // TODO: abort the active documents of every child browsing context.
document.abort(); document.abort(CanGc::note());
// TODO: salvageable flag. // TODO: salvageable flag.
} }
} }
@ -2666,7 +2667,7 @@ impl Document {
// Step 3. // Step 3.
if let Some(parser) = self.get_current_parser() { if let Some(parser) = self.get_current_parser() {
self.active_parser_was_aborted.set(true); self.active_parser_was_aborted.set(true);
parser.abort(); parser.abort(can_gc);
self.salvageable.set(false); self.salvageable.set(false);
} }
} }
@ -3457,6 +3458,7 @@ impl Document {
referrer_policy: Option<ReferrerPolicy>, referrer_policy: Option<ReferrerPolicy>,
status_code: Option<u16>, status_code: Option<u16>,
canceller: FetchCanceller, canceller: FetchCanceller,
can_gc: CanGc,
) -> DomRoot<Document> { ) -> DomRoot<Document> {
Self::new_with_proto( Self::new_with_proto(
window, window,
@ -3474,7 +3476,7 @@ impl Document {
referrer_policy, referrer_policy,
status_code, status_code,
canceller, canceller,
CanGc::note(), can_gc,
) )
} }
@ -3613,7 +3615,7 @@ impl Document {
} }
/// <https://html.spec.whatwg.org/multipage/#appropriate-template-contents-owner-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 self.appropriate_template_contents_owner_document
.or_init(|| { .or_init(|| {
let doctype = if self.is_html_document { let doctype = if self.is_html_document {
@ -3637,6 +3639,7 @@ impl Document {
None, None,
None, None,
Default::default(), Default::default(),
can_gc,
); );
new_doc new_doc
.appropriate_template_contents_owner_document .appropriate_template_contents_owner_document
@ -4351,6 +4354,7 @@ impl DocumentMethods for Document {
&self, &self,
mut local_name: DOMString, mut local_name: DOMString,
options: StringOrElementCreationOptions, options: StringOrElementCreationOptions,
can_gc: CanGc,
) -> Fallible<DomRoot<Element>> { ) -> Fallible<DomRoot<Element>> {
if xml_name_type(&local_name) == Invalid { if xml_name_type(&local_name) == Invalid {
debug!("Not a valid element name"); debug!("Not a valid element name");
@ -4384,6 +4388,7 @@ impl DocumentMethods for Document {
ElementCreator::ScriptCreated, ElementCreator::ScriptCreated,
CustomElementCreationMode::Synchronous, CustomElementCreationMode::Synchronous,
None, None,
can_gc,
)) ))
} }
@ -4393,6 +4398,7 @@ impl DocumentMethods for Document {
namespace: Option<DOMString>, namespace: Option<DOMString>,
qualified_name: DOMString, qualified_name: DOMString,
options: StringOrElementCreationOptions, options: StringOrElementCreationOptions,
can_gc: CanGc,
) -> Fallible<DomRoot<Element>> { ) -> Fallible<DomRoot<Element>> {
let (namespace, prefix, local_name) = validate_and_extract(namespace, &qualified_name)?; let (namespace, prefix, local_name) = validate_and_extract(namespace, &qualified_name)?;
let name = QualName::new(prefix, namespace, local_name); let name = QualName::new(prefix, namespace, local_name);
@ -4409,6 +4415,7 @@ impl DocumentMethods for Document {
ElementCreator::ScriptCreated, ElementCreator::ScriptCreated,
CustomElementCreationMode::Synchronous, CustomElementCreationMode::Synchronous,
None, None,
can_gc,
)) ))
} }
@ -4507,7 +4514,7 @@ impl DocumentMethods for Document {
} }
// https://dom.spec.whatwg.org/#dom-document-importnode // 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. // Step 1.
if node.is::<Document>() || node.is::<ShadowRoot>() { if node.is::<Document>() || node.is::<ShadowRoot>() {
return Err(Error::NotSupported); return Err(Error::NotSupported);
@ -4520,7 +4527,7 @@ impl DocumentMethods for Document {
CloneChildrenFlag::DoNotCloneChildren 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 // https://dom.spec.whatwg.org/#dom-document-adoptnode
@ -4656,7 +4663,7 @@ impl DocumentMethods for Document {
} }
// https://html.spec.whatwg.org/multipage/#document.title // 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() { let root = match self.GetDocumentElement() {
Some(root) => root, Some(root) => root,
None => return, None => return,
@ -4677,6 +4684,7 @@ impl DocumentMethods for Document {
ElementCreator::ScriptCreated, ElementCreator::ScriptCreated,
CustomElementCreationMode::Synchronous, CustomElementCreationMode::Synchronous,
None, None,
can_gc,
); );
let parent = root.upcast::<Node>(); let parent = root.upcast::<Node>();
let child = elem.upcast::<Node>(); let child = elem.upcast::<Node>();
@ -4702,6 +4710,7 @@ impl DocumentMethods for Document {
ElementCreator::ScriptCreated, ElementCreator::ScriptCreated,
CustomElementCreationMode::Synchronous, CustomElementCreationMode::Synchronous,
None, None,
can_gc,
); );
head.upcast::<Node>().AppendChild(elem.upcast()).unwrap() head.upcast::<Node>().AppendChild(elem.upcast()).unwrap()
}, },
@ -5222,7 +5231,7 @@ impl DocumentMethods for Document {
if self.has_browsing_context() { if self.has_browsing_context() {
// spec says "stop document loading", // spec says "stop document loading",
// which is a process that does more than just abort // which is a process that does more than just abort
self.abort(); self.abort(CanGc::note());
} }
// Step 9 // Step 9
@ -5296,7 +5305,7 @@ impl DocumentMethods for Document {
} }
// https://html.spec.whatwg.org/multipage/#dom-document-write // 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() { if !self.is_html_document() {
// Step 1. // Step 1.
return Err(Error::InvalidState); return Err(Error::InvalidState);
@ -5334,20 +5343,20 @@ impl DocumentMethods for Document {
// TODO: handle reload override buffer. // TODO: handle reload override buffer.
// Steps 6-8. // Steps 6-8.
parser.write(text); parser.write(text, can_gc);
// Step 9. // Step 9.
Ok(()) Ok(())
} }
// https://html.spec.whatwg.org/multipage/#dom-document-writeln // 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()); text.push("\n".into());
self.Write(text) self.Write(text, can_gc)
} }
// https://html.spec.whatwg.org/multipage/#dom-document-close // 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() { if !self.is_html_document() {
// Step 1. // Step 1.
return Err(Error::InvalidState); return Err(Error::InvalidState);
@ -5367,7 +5376,7 @@ impl DocumentMethods for Document {
}; };
// Step 4-6. // Step 4-6.
parser.close(); parser.close(can_gc);
Ok(()) Ok(())
} }

View file

@ -28,6 +28,7 @@ use crate::dom::htmltitleelement::HTMLTitleElement;
use crate::dom::node::Node; use crate::dom::node::Node;
use crate::dom::text::Text; use crate::dom::text::Text;
use crate::dom::xmldocument::XMLDocument; use crate::dom::xmldocument::XMLDocument;
use crate::script_runtime::CanGc;
// https://dom.spec.whatwg.org/#domimplementation // https://dom.spec.whatwg.org/#domimplementation
#[dom_struct] #[dom_struct]
@ -74,6 +75,7 @@ impl DOMImplementationMethods for DOMImplementation {
maybe_namespace: Option<DOMString>, maybe_namespace: Option<DOMString>,
qname: DOMString, qname: DOMString,
maybe_doctype: Option<&DocumentType>, maybe_doctype: Option<&DocumentType>,
can_gc: CanGc,
) -> Fallible<DomRoot<XMLDocument>> { ) -> Fallible<DomRoot<XMLDocument>> {
let win = self.document.window(); let win = self.document.window();
let loader = DocumentLoader::new(&self.document.loader()); let loader = DocumentLoader::new(&self.document.loader());
@ -108,7 +110,7 @@ impl DOMImplementationMethods for DOMImplementation {
}); });
match doc match doc
.upcast::<Document>() .upcast::<Document>()
.CreateElementNS(maybe_namespace, qname, options) .CreateElementNS(maybe_namespace, qname, options, can_gc)
{ {
Err(error) => return Err(error), Err(error) => return Err(error),
Ok(elem) => Some(elem), Ok(elem) => Some(elem),
@ -137,7 +139,7 @@ impl DOMImplementationMethods for DOMImplementation {
} }
// https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument // 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 win = self.document.window();
let loader = DocumentLoader::new(&self.document.loader()); let loader = DocumentLoader::new(&self.document.loader());
@ -157,6 +159,7 @@ impl DOMImplementationMethods for DOMImplementation {
None, None,
None, None,
Default::default(), Default::default(),
can_gc,
); );
{ {

View file

@ -62,6 +62,7 @@ impl DOMParserMethods for DOMParser {
&self, &self,
s: DOMString, s: DOMString,
ty: DOMParserBinding::SupportedType, ty: DOMParserBinding::SupportedType,
can_gc: CanGc,
) -> Fallible<DomRoot<Document>> { ) -> Fallible<DomRoot<Document>> {
let url = self.window.get_url(); let url = self.window.get_url();
let content_type = ty let content_type = ty
@ -87,8 +88,9 @@ impl DOMParserMethods for DOMParser {
None, None,
None, None,
Default::default(), 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); document.set_ready_state(DocumentReadyState::Complete);
Ok(document) Ok(document)
}, },
@ -108,8 +110,9 @@ impl DOMParserMethods for DOMParser {
None, None,
None, None,
Default::default(), 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); document.set_ready_state(DocumentReadyState::Complete);
Ok(document) Ok(document)
}, },

View file

@ -148,6 +148,7 @@ use crate::dom::validation::Validatable;
use crate::dom::validitystate::ValidationFlags; use crate::dom::validitystate::ValidationFlags;
use crate::dom::virtualmethods::{vtable_for, VirtualMethods}; use crate::dom::virtualmethods::{vtable_for, VirtualMethods};
use crate::dom::window::ReflowReason; use crate::dom::window::ReflowReason;
use crate::script_runtime::CanGc;
use crate::script_thread::ScriptThread; use crate::script_thread::ScriptThread;
use crate::stylesheet_loader::StylesheetOwner; use crate::stylesheet_loader::StylesheetOwner;
use crate::task::TaskOnce; use crate::task::TaskOnce;
@ -262,8 +263,9 @@ impl Element {
creator: ElementCreator, creator: ElementCreator,
mode: CustomElementCreationMode, mode: CustomElementCreationMode,
proto: Option<HandleObject>, proto: Option<HandleObject>,
can_gc: CanGc,
) -> DomRoot<Element> { ) -> DomRoot<Element> {
create_element(name, is, document, creator, mode, proto) create_element(name, is, document, creator, mode, proto, can_gc)
} }
pub fn new_inherited( pub fn new_inherited(
@ -397,7 +399,7 @@ impl Element {
} }
} }
pub fn invoke_reactions(&self) { pub fn invoke_reactions(&self, _can_gc: CanGc) {
loop { loop {
rooted_vec!(let mut reactions); rooted_vec!(let mut reactions);
match *self.rare_data_mut() { match *self.rare_data_mut() {
@ -412,7 +414,7 @@ impl Element {
} }
for reaction in reactions.iter() { for reaction in reactions.iter() {
reaction.invoke(self); reaction.invoke(self, CanGc::note());
} }
reactions.clear(); reactions.clear();
@ -1872,15 +1874,19 @@ impl Element {
} }
// https://w3c.github.io/DOM-Parsing/#parsing // 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. // Steps 1-2.
// TODO(#11995): XML case. // 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. // Step 3.
// See https://github.com/w3c/DOM-Parsing/issues/61. // See https://github.com/w3c/DOM-Parsing/issues/61.
let context_document = { let context_document = {
if let Some(template) = self.downcast::<HTMLTemplateElement>() { if let Some(template) = self.downcast::<HTMLTemplateElement>() {
template.Content().upcast::<Node>().owner_doc() template.Content(CanGc::note()).upcast::<Node>().owner_doc()
} else { } else {
document_from_node(self) document_from_node(self)
} }
@ -2633,11 +2639,11 @@ impl ElementMethods for Element {
} }
/// <https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML> /// <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. // Step 2.
// https://github.com/w3c/DOM-Parsing/issues/1 // https://github.com/w3c/DOM-Parsing/issues/1
let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() { let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
DomRoot::upcast(template.Content()) DomRoot::upcast(template.Content(can_gc))
} else { } else {
DomRoot::from_ref(self.upcast()) DomRoot::from_ref(self.upcast())
}; };
@ -2656,7 +2662,7 @@ impl ElementMethods for Element {
} }
// Step 1. // Step 1.
let frag = self.parse_fragment(value)?; let frag = self.parse_fragment(value, CanGc::note())?;
Node::replace_all(Some(frag.upcast()), &target); Node::replace_all(Some(frag.upcast()), &target);
Ok(()) Ok(())
@ -2672,7 +2678,7 @@ impl ElementMethods for Element {
} }
// https://w3c.github.io/DOM-Parsing/#dom-element-outerhtml // 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_document = document_from_node(self);
let context_node = self.upcast::<Node>(); let context_node = self.upcast::<Node>();
// Step 1. // Step 1.
@ -2697,6 +2703,7 @@ impl ElementMethods for Element {
ElementCreator::ScriptCreated, ElementCreator::ScriptCreated,
CustomElementCreationMode::Synchronous, CustomElementCreationMode::Synchronous,
None, None,
can_gc,
); );
DomRoot::upcast(body_elem) DomRoot::upcast(body_elem)
}, },
@ -2704,7 +2711,7 @@ impl ElementMethods for Element {
}; };
// Step 5. // Step 5.
let frag = parent.parse_fragment(value)?; let frag = parent.parse_fragment(value, CanGc::note())?;
// Step 6. // Step 6.
context_parent.ReplaceChild(frag.upcast(), context_node)?; context_parent.ReplaceChild(frag.upcast(), context_node)?;
Ok(()) Ok(())
@ -2862,7 +2869,12 @@ impl ElementMethods for Element {
} }
// https://w3c.github.io/DOM-Parsing/#dom-element-insertadjacenthtml // 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. // Step 1.
let position = position.parse::<AdjacentPosition>()?; let position = position.parse::<AdjacentPosition>()?;
@ -2886,7 +2898,7 @@ impl ElementMethods for Element {
Element::fragment_parsing_context(&context.owner_doc(), context.downcast::<Element>()); Element::fragment_parsing_context(&context.owner_doc(), context.downcast::<Element>());
// Step 3. // Step 3.
let fragment = context.parse_fragment(text)?; let fragment = context.parse_fragment(text, can_gc)?;
// Step 4. // Step 4.
self.insert_adjacent(position, fragment.upcast()) self.insert_adjacent(position, fragment.upcast())

View file

@ -120,7 +120,8 @@ use crate::microtask::{Microtask, MicrotaskQueue, UserMicrotask};
use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; use crate::realms::{enter_realm, AlreadyInRealm, InRealm};
use crate::script_module::{DynamicModuleList, ModuleScript, ModuleTree, ScriptFetchOptions}; use crate::script_module::{DynamicModuleList, ModuleScript, ModuleTree, ScriptFetchOptions};
use crate::script_runtime::{ 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::script_thread::{MainThreadScriptChan, ScriptThread};
use crate::security_manager::CSPViolationReporter; use crate::security_manager::CSPViolationReporter;
@ -2952,13 +2953,14 @@ impl GlobalScope {
} }
/// Perform a microtask checkpoint. /// 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. // Only perform the checkpoint if we're not shutting down.
if self.can_continue_running() { if self.can_continue_running() {
self.microtask_queue.checkpoint( self.microtask_queue.checkpoint(
GlobalScope::get_cx(), GlobalScope::get_cx(),
|_| Some(DomRoot::from_ref(self)), |_| Some(DomRoot::from_ref(self)),
vec![DomRoot::from_ref(self)], vec![DomRoot::from_ref(self)],
can_gc,
); );
} }
} }

View file

@ -56,7 +56,7 @@ impl HTMLAudioElement {
pub fn Audio( pub fn Audio(
window: &Window, window: &Window,
proto: Option<HandleObject>, proto: Option<HandleObject>,
_can_gc: CanGc, can_gc: CanGc,
src: Option<DOMString>, src: Option<DOMString>,
) -> Fallible<DomRoot<HTMLAudioElement>> { ) -> Fallible<DomRoot<HTMLAudioElement>> {
let element = Element::create( let element = Element::create(
@ -66,6 +66,7 @@ impl HTMLAudioElement {
ElementCreator::ScriptCreated, ElementCreator::ScriptCreated,
CustomElementCreationMode::Synchronous, CustomElementCreationMode::Synchronous,
proto, proto,
can_gc,
); );
let audio = DomRoot::downcast::<HTMLAudioElement>(element).unwrap(); let audio = DomRoot::downcast::<HTMLAudioElement>(element).unwrap();

View file

@ -40,6 +40,7 @@ use crate::dom::node::{
}; };
use crate::dom::virtualmethods::VirtualMethods; use crate::dom::virtualmethods::VirtualMethods;
use crate::dom::windowproxy::WindowProxy; use crate::dom::windowproxy::WindowProxy;
use crate::script_runtime::CanGc;
use crate::script_thread::ScriptThread; use crate::script_thread::ScriptThread;
#[derive(Clone, Copy, JSTraceable, MallocSizeOf)] #[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
@ -114,8 +115,9 @@ impl HTMLIFrameElement {
&self, &self,
load_data: LoadData, load_data: LoadData,
replace: HistoryEntryReplacement, 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( fn start_new_pipeline(
@ -123,6 +125,7 @@ impl HTMLIFrameElement {
mut load_data: LoadData, mut load_data: LoadData,
pipeline_type: PipelineType, pipeline_type: PipelineType,
replace: HistoryEntryReplacement, replace: HistoryEntryReplacement,
can_gc: CanGc,
) { ) {
let sandboxed = if self.is_sandboxed() { let sandboxed = if self.is_sandboxed() {
IFrameSandboxed IFrameSandboxed
@ -146,7 +149,7 @@ impl HTMLIFrameElement {
let mut load_blocker = self.load_blocker.borrow_mut(); let mut load_blocker = self.load_blocker.borrow_mut();
// Any oustanding load is finished from the point of view of the blocked // Any oustanding load is finished from the point of view of the blocked
// document; the new navigation will continue blocking it. // 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" { if load_data.url.scheme() == "javascript" {
@ -241,7 +244,7 @@ impl HTMLIFrameElement {
} }
/// <https://html.spec.whatwg.org/multipage/#process-the-iframe-attributes> /// <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: // > 1. If `element`'s `srcdoc` attribute is specified, then:
if self if self
.upcast::<Element>() .upcast::<Element>()
@ -264,6 +267,7 @@ impl HTMLIFrameElement {
self.navigate_or_reload_child_browsing_context( self.navigate_or_reload_child_browsing_context(
load_data, load_data,
HistoryEntryReplacement::Disabled, HistoryEntryReplacement::Disabled,
can_gc,
); );
return; return;
} }
@ -347,10 +351,10 @@ impl HTMLIFrameElement {
} else { } else {
HistoryEntryReplacement::Disabled 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 // Synchronously create a new browsing context, which will present
// `about:blank`. (This is not a navigation.) // `about:blank`. (This is not a navigation.)
// //
@ -389,6 +393,7 @@ impl HTMLIFrameElement {
load_data, load_data,
PipelineType::InitialAboutBlank, PipelineType::InitialAboutBlank,
HistoryEntryReplacement::Disabled, HistoryEntryReplacement::Disabled,
can_gc,
); );
} }
@ -400,7 +405,12 @@ impl HTMLIFrameElement {
self.browsing_context_id.set(None); 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) && if self.pending_pipeline_id.get() != Some(new_pipeline_id) &&
reason == UpdatePipelineIdReason::Navigation reason == UpdatePipelineIdReason::Navigation
{ {
@ -413,7 +423,7 @@ impl HTMLIFrameElement {
// The load blocker will be terminated for a navigation in iframe_load_event_steps. // The load blocker will be terminated for a navigation in iframe_load_event_steps.
if reason == UpdatePipelineIdReason::Traversal { if reason == UpdatePipelineIdReason::Traversal {
let mut blocker = self.load_blocker.borrow_mut(); let mut blocker = self.load_blocker.borrow_mut();
LoadBlocker::terminate(&mut blocker); LoadBlocker::terminate(&mut blocker, can_gc);
} }
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); 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 /// <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 // 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(). // can guarantee that it's created for the case of iframe.reload().
if Some(loaded_pipeline) != self.pending_pipeline_id.get() { if Some(loaded_pipeline) != self.pending_pipeline_id.get() {
@ -495,7 +505,7 @@ impl HTMLIFrameElement {
self.upcast::<EventTarget>().fire_event(atom!("load")); self.upcast::<EventTarget>().fire_event(atom!("load"));
let mut blocker = self.load_blocker.borrow_mut(); 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 // 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 // trigger the processing of iframe attributes whenever "srcdoc" attribute is set, changed or removed
if self.upcast::<Node>().is_connected_with_browsing_context() { if self.upcast::<Node>().is_connected_with_browsing_context() {
debug!("iframe srcdoc modified while in 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") => { local_name!("src") => {
@ -681,7 +691,7 @@ impl VirtualMethods for HTMLIFrameElement {
// the child browsing context to be created. // the child browsing context to be created.
if self.upcast::<Node>().is_connected_with_browsing_context() { if self.upcast::<Node>().is_connected_with_browsing_context() {
debug!("iframe src set while in 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() { if this.upcast::<Node>().is_connected_with_browsing_context() {
debug!("iframe bound to browsing context."); debug!("iframe bound to browsing context.");
debug_assert!(tree_connected, "is_connected_with_bc, but not tree_connected"); debug_assert!(tree_connected, "is_connected_with_bc, but not tree_connected");
this.create_nested_browsing_context(); this.create_nested_browsing_context(CanGc::note());
this.process_the_iframe_attributes(ProcessingMode::FirstTime); 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); self.super_type().unwrap().unbind_from_tree(context);
let mut blocker = self.load_blocker.borrow_mut(); 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 // https://html.spec.whatwg.org/multipage/#a-browsing-context-is-discarded
let window = window_from_node(self); let window = window_from_node(self);

View file

@ -332,7 +332,7 @@ pub(crate) fn image_fetch_request(
#[allow(non_snake_case)] #[allow(non_snake_case)]
impl HTMLImageElement { impl HTMLImageElement {
/// Update the current image with a valid URL. /// 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 window = window_from_node(self);
let image_cache = window.image_cache(); let image_cache = window.image_cache();
let sender = generate_cache_listener_for_element(self); let sender = generate_cache_listener_for_element(self);
@ -351,17 +351,20 @@ impl HTMLImageElement {
is_placeholder, is_placeholder,
}) => { }) => {
if is_placeholder { if is_placeholder {
self.process_image_response(ImageResponse::PlaceholderLoaded(image, url)) self.process_image_response(
ImageResponse::PlaceholderLoaded(image, url),
can_gc,
)
} else { } else {
self.process_image_response(ImageResponse::Loaded(image, url)) self.process_image_response(ImageResponse::Loaded(image, url), can_gc)
} }
}, },
ImageCacheResult::Available(ImageOrMetadataAvailable::MetadataAvailable(m)) => { ImageCacheResult::Available(ImageOrMetadataAvailable::MetadataAvailable(m)) => {
self.process_image_response(ImageResponse::MetadataLoaded(m)) self.process_image_response(ImageResponse::MetadataLoaded(m), can_gc)
}, },
ImageCacheResult::Pending(_) => (), ImageCacheResult::Pending(_) => (),
ImageCacheResult::ReadyForRequest(id) => self.fetch_request(img_url, id), 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. // 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 { self.current_request.borrow_mut().metadata = Some(ImageMetadata {
height: image.height, height: image.height,
width: image.width, width: image.width,
@ -426,34 +429,34 @@ impl HTMLImageElement {
self.current_request.borrow_mut().final_url = Some(url); self.current_request.borrow_mut().final_url = Some(url);
self.current_request.borrow_mut().image = Some(image); self.current_request.borrow_mut().image = Some(image);
self.current_request.borrow_mut().state = State::CompletelyAvailable; 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 // Mark the node dirty
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
self.resolve_image_decode_promises(); self.resolve_image_decode_promises();
} }
/// Step 24 of <https://html.spec.whatwg.org/multipage/#update-the-image-data> /// 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 // TODO: Handle multipart/x-mixed-replace
let (trigger_image_load, trigger_image_error) = match (image, self.image_request.get()) { let (trigger_image_load, trigger_image_error) = match (image, self.image_request.get()) {
(ImageResponse::Loaded(image, url), ImageRequestPhase::Current) => { (ImageResponse::Loaded(image, url), ImageRequestPhase::Current) => {
self.handle_loaded_image(image, url); self.handle_loaded_image(image, url, can_gc);
(true, false) (true, false)
}, },
(ImageResponse::PlaceholderLoaded(image, url), ImageRequestPhase::Current) => { (ImageResponse::PlaceholderLoaded(image, url), ImageRequestPhase::Current) => {
self.handle_loaded_image(image, url); self.handle_loaded_image(image, url, can_gc);
(false, true) (false, true)
}, },
(ImageResponse::Loaded(image, url), ImageRequestPhase::Pending) => { (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.image_request.set(ImageRequestPhase::Current);
self.handle_loaded_image(image, url); self.handle_loaded_image(image, url, CanGc::note());
(true, false) (true, false)
}, },
(ImageResponse::PlaceholderLoaded(image, url), ImageRequestPhase::Pending) => { (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.image_request.set(ImageRequestPhase::Current);
self.handle_loaded_image(image, url); self.handle_loaded_image(image, url, CanGc::note());
(false, true) (false, true)
}, },
(ImageResponse::MetadataLoaded(meta), ImageRequestPhase::Current) => { (ImageResponse::MetadataLoaded(meta), ImageRequestPhase::Current) => {
@ -466,12 +469,12 @@ impl HTMLImageElement {
(false, false) (false, false)
}, },
(ImageResponse::None, ImageRequestPhase::Current) => { (ImageResponse::None, ImageRequestPhase::Current) => {
self.abort_request(State::Broken, ImageRequestPhase::Current); self.abort_request(State::Broken, ImageRequestPhase::Current, can_gc);
(false, true) (false, true)
}, },
(ImageResponse::None, ImageRequestPhase::Pending) => { (ImageResponse::None, ImageRequestPhase::Pending) => {
self.abort_request(State::Broken, ImageRequestPhase::Current); self.abort_request(State::Broken, ImageRequestPhase::Current, can_gc);
self.abort_request(State::Broken, ImageRequestPhase::Pending); self.abort_request(State::Broken, ImageRequestPhase::Pending, CanGc::note());
self.image_request.set(ImageRequestPhase::Current); self.image_request.set(ImageRequestPhase::Current);
(false, true) (false, true)
}, },
@ -501,6 +504,7 @@ impl HTMLImageElement {
src: USVString, src: USVString,
generation: u32, generation: u32,
selected_pixel_density: f64, selected_pixel_density: f64,
can_gc: CanGc,
) { ) {
match image { match image {
ImageResponse::Loaded(image, url) | ImageResponse::PlaceholderLoaded(image, url) => { 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().final_url = Some(url);
self.pending_request.borrow_mut().image = Some(image); 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) => { ImageResponse::MetadataLoaded(meta) => {
self.pending_request.borrow_mut().metadata = Some(meta); self.pending_request.borrow_mut().metadata = Some(meta);
}, },
ImageResponse::None => { 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> /// <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 { let mut request = match request {
ImageRequestPhase::Current => self.current_request.borrow_mut(), ImageRequestPhase::Current => self.current_request.borrow_mut(),
ImageRequestPhase::Pending => self.pending_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.state = state;
request.image = None; request.image = None;
request.metadata = None; request.metadata = None;
@ -804,18 +813,25 @@ impl HTMLImageElement {
request: &mut RefMut<ImageRequest>, request: &mut RefMut<ImageRequest>,
url: &ServoUrl, url: &ServoUrl,
src: &USVString, src: &USVString,
can_gc: CanGc,
) { ) {
request.parsed_url = Some(url.clone()); request.parsed_url = Some(url.clone());
request.source_url = Some(src.clone()); request.source_url = Some(src.clone());
request.image = None; request.image = None;
request.metadata = None; request.metadata = None;
let document = document_from_node(self); 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()))); request.blocker = Some(LoadBlocker::new(&document, LoadType::Image(url.clone())));
} }
/// Step 13-17 of html.spec.whatwg.org/multipage/#update-the-image-data /// 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() { match self.image_request.get() {
ImageRequestPhase::Pending => { ImageRequestPhase::Pending => {
if let Some(pending_url) = self.pending_request.borrow().parsed_url.clone() { if let Some(pending_url) = self.pending_request.borrow().parsed_url.clone() {
@ -836,33 +852,33 @@ impl HTMLImageElement {
// Step 15 abort pending request // Step 15 abort pending request
pending_request.image = None; pending_request.image = None;
pending_request.parsed_url = 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 // TODO: queue a task to restart animation, if restart-animation is set
return; return;
} }
pending_request.current_pixel_density = Some(selected_pixel_density); pending_request.current_pixel_density = Some(selected_pixel_density);
self.image_request.set(ImageRequestPhase::Pending); 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) => { (_, State::Broken) | (_, State::Unavailable) => {
// Step 17 // Step 17
current_request.current_pixel_density = Some(selected_pixel_density); 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 // step 17
pending_request.current_pixel_density = Some(selected_pixel_density); pending_request.current_pixel_density = Some(selected_pixel_density);
self.image_request.set(ImageRequestPhase::Pending); 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 /// 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 document = document_from_node(self);
let window = document.window(); let window = document.window();
let task_source = window.task_manager().dom_manipulation_task_source(); let task_source = window.task_manager().dom_manipulation_task_source();
@ -871,8 +887,8 @@ impl HTMLImageElement {
// Step 8 // Step 8
Some(data) => data, Some(data) => data,
None => { None => {
self.abort_request(State::Broken, ImageRequestPhase::Current); self.abort_request(State::Broken, ImageRequestPhase::Current, can_gc);
self.abort_request(State::Broken, ImageRequestPhase::Pending); self.abort_request(State::Broken, ImageRequestPhase::Pending, CanGc::note());
// Step 9. // Step 9.
// FIXME(nox): Why are errors silenced here? // FIXME(nox): Why are errors silenced here?
let _ = task_source.queue( let _ = task_source.queue(
@ -903,11 +919,11 @@ impl HTMLImageElement {
match parsed_url { match parsed_url {
Ok(url) => { Ok(url) => {
// Step 13-17 // Step 13-17
self.prepare_image_request(&url, &src, pixel_density); self.prepare_image_request(&url, &src, pixel_density, can_gc);
}, },
Err(_) => { Err(_) => {
self.abort_request(State::Broken, ImageRequestPhase::Current); self.abort_request(State::Broken, ImageRequestPhase::Current, can_gc);
self.abort_request(State::Broken, ImageRequestPhase::Pending); self.abort_request(State::Broken, ImageRequestPhase::Pending, CanGc::note());
// Step 12.1-12.5. // Step 12.1-12.5.
let src = src.0; let src = src.0;
// FIXME(nox): Why are errors silenced here? // FIXME(nox): Why are errors silenced here?
@ -929,7 +945,7 @@ impl HTMLImageElement {
} }
/// <https://html.spec.whatwg.org/multipage/#update-the-image-data> /// <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 document = document_from_node(self);
let window = document.window(); let window = document.window();
let elem = self.upcast::<Element>(); let elem = self.upcast::<Element>();
@ -990,8 +1006,16 @@ impl HTMLImageElement {
width: image.width, width: image.width,
}; };
// Step 6.3.2 abort requests // Step 6.3.2 abort requests
self.abort_request(State::CompletelyAvailable, ImageRequestPhase::Current); self.abort_request(
self.abort_request(State::Unavailable, ImageRequestPhase::Pending); State::CompletelyAvailable,
ImageRequestPhase::Current,
can_gc,
);
self.abort_request(
State::Unavailable,
ImageRequestPhase::Pending,
CanGc::note(),
);
let mut current_request = self.current_request.borrow_mut(); let mut current_request = self.current_request.borrow_mut();
current_request.final_url = Some(img_url.clone()); current_request.final_url = Some(img_url.clone());
current_request.image = Some(image.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> /// 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 // TODO reduce duplicacy of this code
fn generate_cache_listener_for_element( fn generate_cache_listener_for_element(
elem: &HTMLImageElement, elem: &HTMLImageElement,
selected_source: String, selected_source: String,
selected_pixel_density: f64, selected_pixel_density: f64,
_can_gc: CanGc,
) -> IpcSender<PendingImageResponse> { ) -> IpcSender<PendingImageResponse> {
let trusted_node = Trusted::new(elem); let trusted_node = Trusted::new(elem);
let (responder_sender, responder_receiver) = ipc::channel().unwrap(); 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. // Ignore any image response for a previous request that has been discarded.
if generation == element.generation.get() { if generation == element.generation.get() {
element.process_image_response_for_environment_change(image, 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, &canceller,
@ -1124,6 +1150,7 @@ impl HTMLImageElement {
&mut self.pending_request.borrow_mut(), &mut self.pending_request.borrow_mut(),
&img_url, &img_url,
&selected_source, &selected_source,
CanGc::note(),
); );
let window = window_from_node(self); let window = window_from_node(self);
@ -1134,6 +1161,7 @@ impl HTMLImageElement {
self, self,
selected_source.0.clone(), selected_source.0.clone(),
selected_pixel_density, selected_pixel_density,
CanGc::note(),
); );
let cache_result = image_cache.track_image( let cache_result = image_cache.track_image(
img_url.clone(), img_url.clone(),
@ -1150,6 +1178,7 @@ impl HTMLImageElement {
selected_source, selected_source,
generation, generation,
selected_pixel_density, selected_pixel_density,
can_gc,
) )
}, },
ImageCacheResult::Available(ImageOrMetadataAvailable::MetadataAvailable(m)) => { ImageCacheResult::Available(ImageOrMetadataAvailable::MetadataAvailable(m)) => {
@ -1158,6 +1187,7 @@ impl HTMLImageElement {
selected_source, selected_source,
generation, generation,
selected_pixel_density, selected_pixel_density,
can_gc,
); );
}, },
ImageCacheResult::LoadError => { ImageCacheResult::LoadError => {
@ -1166,6 +1196,7 @@ impl HTMLImageElement {
selected_source, selected_source,
generation, generation,
selected_pixel_density, selected_pixel_density,
can_gc,
); );
}, },
ImageCacheResult::ReadyForRequest(id) => self.fetch_request(&img_url, id), ImageCacheResult::ReadyForRequest(id) => self.fetch_request(&img_url, id),
@ -1221,6 +1252,7 @@ impl HTMLImageElement {
src: USVString, src: USVString,
generation: u32, generation: u32,
selected_pixel_density: f64, selected_pixel_density: f64,
can_gc: CanGc,
) { ) {
let this = Trusted::new(self); let this = Trusted::new(self);
let window = window_from_node(self); let window = window_from_node(self);
@ -1231,7 +1263,7 @@ impl HTMLImageElement {
let relevant_mutation = this.generation.get() != generation; let relevant_mutation = this.generation.get() != generation;
// Step 15.1 // Step 15.1
if relevant_mutation { if relevant_mutation {
this.abort_request(State::Unavailable, ImageRequestPhase::Pending); this.abort_request(State::Unavailable, ImageRequestPhase::Pending, can_gc);
return; return;
} }
// Step 15.2 // Step 15.2
@ -1249,7 +1281,7 @@ impl HTMLImageElement {
// Step 15.5 // Step 15.5
mem::swap(&mut this.current_request.borrow_mut(), &mut pending_request); 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 // Step 15.6
@ -1326,7 +1358,7 @@ impl HTMLImageElement {
pub fn Image( pub fn Image(
window: &Window, window: &Window,
proto: Option<HandleObject>, proto: Option<HandleObject>,
_can_gc: CanGc, can_gc: CanGc,
width: Option<u32>, width: Option<u32>,
height: Option<u32>, height: Option<u32>,
) -> Fallible<DomRoot<HTMLImageElement>> { ) -> Fallible<DomRoot<HTMLImageElement>> {
@ -1337,6 +1369,7 @@ impl HTMLImageElement {
ElementCreator::ScriptCreated, ElementCreator::ScriptCreated,
CustomElementCreationMode::Synchronous, CustomElementCreationMode::Synchronous,
proto, proto,
can_gc,
); );
let image = DomRoot::downcast::<HTMLImageElement>(element).unwrap(); let image = DomRoot::downcast::<HTMLImageElement>(element).unwrap();
@ -1349,7 +1382,7 @@ impl HTMLImageElement {
// run update_the_image_data when the element is created. // run update_the_image_data when the element is created.
// https://html.spec.whatwg.org/multipage/#when-to-obtain-images // https://html.spec.whatwg.org/multipage/#when-to-obtain-images
image.update_the_image_data(); image.update_the_image_data(CanGc::note());
Ok(image) Ok(image)
} }
@ -1415,7 +1448,7 @@ pub enum ImageElementMicrotask {
} }
impl MicrotaskRunnable for ImageElementMicrotask { impl MicrotaskRunnable for ImageElementMicrotask {
fn handler(&self) { fn handler(&self, can_gc: CanGc) {
match *self { match *self {
ImageElementMicrotask::StableStateUpdateImageDataTask { ImageElementMicrotask::StableStateUpdateImageDataTask {
ref elem, ref elem,
@ -1424,14 +1457,14 @@ impl MicrotaskRunnable for ImageElementMicrotask {
// Step 7 of https://html.spec.whatwg.org/multipage/#update-the-image-data, // Step 7 of https://html.spec.whatwg.org/multipage/#update-the-image-data,
// stop here if other instances of this algorithm have been scheduled // stop here if other instances of this algorithm have been scheduled
if elem.generation.get() == *generation { if elem.generation.get() == *generation {
elem.update_the_image_data_sync_steps(); elem.update_the_image_data_sync_steps(can_gc);
} }
}, },
ImageElementMicrotask::EnvironmentChangesTask { ImageElementMicrotask::EnvironmentChangesTask {
ref elem, ref elem,
ref generation, ref generation,
} => { } => {
elem.react_to_environment_changes_sync_steps(*generation); elem.react_to_environment_changes_sync_steps(*generation, can_gc);
}, },
ImageElementMicrotask::DecodeTask { ImageElementMicrotask::DecodeTask {
ref elem, ref elem,
@ -1739,7 +1772,7 @@ impl VirtualMethods for HTMLImageElement {
fn adopting_steps(&self, old_doc: &Document) { fn adopting_steps(&self, old_doc: &Document) {
self.super_type().unwrap().adopting_steps(old_doc); 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) { fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
@ -1750,7 +1783,7 @@ impl VirtualMethods for HTMLImageElement {
&local_name!("width") | &local_name!("width") |
&local_name!("crossorigin") | &local_name!("crossorigin") |
&local_name!("sizes") | &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 // https://html.spec.whatwg.org/multipage/#relevant-mutations
if let Some(parent) = self.upcast::<Node>().GetParentElement() { if let Some(parent) = self.upcast::<Node>().GetParentElement() {
if parent.is::<HTMLPictureElement>() { 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 // The element is removed from a picture parent element
// https://html.spec.whatwg.org/multipage/#relevant-mutations // https://html.spec.whatwg.org/multipage/#relevant-mutations
if context.parent.is::<HTMLPictureElement>() { 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) { fn process_image_response(&self, response: ImageResponse) {
self.process_image_response(response); self.process_image_response(response, CanGc::note());
} }
} }

View file

@ -101,6 +101,7 @@ use crate::fetch::{create_a_potential_cors_request, FetchCanceller};
use crate::microtask::{Microtask, MicrotaskRunnable}; use crate::microtask::{Microtask, MicrotaskRunnable};
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
use crate::realms::{enter_realm, InRealm}; use crate::realms::{enter_realm, InRealm};
use crate::script_runtime::CanGc;
use crate::script_thread::ScriptThread; use crate::script_thread::ScriptThread;
use crate::task_source::TaskSource; use crate::task_source::TaskSource;
@ -496,12 +497,12 @@ impl HTMLMediaElement {
/// we pass true to that method again. /// we pass true to that method again.
/// ///
/// <https://html.spec.whatwg.org/multipage/#delaying-the-load-event-flag> /// <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(); let mut blocker = self.delaying_the_load_event_flag.borrow_mut();
if delay && blocker.is_none() { if delay && blocker.is_none() {
*blocker = Some(LoadBlocker::new(&document_from_node(self), LoadType::Media)); *blocker = Some(LoadBlocker::new(&document_from_node(self), LoadType::Media));
} else if !delay && blocker.is_some() { } 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 // 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(); let old_ready_state = self.ready_state.get();
self.ready_state.set(ready_state); self.ready_state.set(ready_state);
@ -638,7 +639,7 @@ impl HTMLMediaElement {
task!(media_reached_current_data: move || { task!(media_reached_current_data: move || {
let this = this.root(); let this = this.root();
this.upcast::<EventTarget>().fire_event(atom!("loadeddata")); this.upcast::<EventTarget>().fire_event(atom!("loadeddata"));
this.delay_load_event(false); this.delay_load_event(false, can_gc);
}), }),
window.upcast(), window.upcast(),
); );
@ -697,7 +698,7 @@ impl HTMLMediaElement {
} }
// https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm // 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. // Step 1.
self.network_state.set(NetworkState::NoSource); self.network_state.set(NetworkState::NoSource);
@ -705,7 +706,7 @@ impl HTMLMediaElement {
self.set_show_poster(true); self.set_show_poster(true);
// Step 3. // Step 3.
self.delay_load_event(true); self.delay_load_event(true, can_gc);
// Step 4. // Step 4.
// If the resource selection mode in the synchronous section is // 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 // 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. // Step 5.
// FIXME(ferjm): Implement blocked_on_parser logic // FIXME(ferjm): Implement blocked_on_parser logic
// https://html.spec.whatwg.org/multipage/#blocked-on-parser // https://html.spec.whatwg.org/multipage/#blocked-on-parser
@ -765,7 +766,7 @@ impl HTMLMediaElement {
} else { } else {
self.network_state.set(NetworkState::Empty); self.network_state.set(NetworkState::Empty);
// https://github.com/whatwg/html/issues/3065 // https://github.com/whatwg/html/issues/3065
self.delay_load_event(false); self.delay_load_event(false, can_gc);
return; return;
}; };
@ -792,12 +793,12 @@ impl HTMLMediaElement {
// Step 9.obj.3. // Step 9.obj.3.
// Note that the resource fetch algorithm itself takes care // Note that the resource fetch algorithm itself takes care
// of the cleanup in case of failure itself. // 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) => { Mode::Attribute(src) => {
// Step 9.attr.1. // Step 9.attr.1.
if src.is_empty() { if src.is_empty() {
self.queue_dedicated_media_source_failure_steps(); self.queue_dedicated_media_source_failure_steps(can_gc);
return; return;
} }
@ -805,7 +806,7 @@ impl HTMLMediaElement {
let url_record = match base_url.join(&src) { let url_record = match base_url.join(&src) {
Ok(url) => url, Ok(url) => url,
Err(_) => { Err(_) => {
self.queue_dedicated_media_source_failure_steps(); self.queue_dedicated_media_source_failure_steps(can_gc);
return; return;
}, },
}; };
@ -816,7 +817,7 @@ impl HTMLMediaElement {
// Step 9.attr.4. // Step 9.attr.4.
// Note that the resource fetch algorithm itself takes care // Note that the resource fetch algorithm itself takes care
// of the cleanup in case of failure itself. // 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. // Step 9.children.
Mode::Children(source) => { Mode::Children(source) => {
@ -826,7 +827,7 @@ impl HTMLMediaElement {
// Step 9.attr.2. // Step 9.attr.2.
if src.is_empty() { if src.is_empty() {
source.upcast::<EventTarget>().fire_event(atom!("error")); source.upcast::<EventTarget>().fire_event(atom!("error"));
self.queue_dedicated_media_source_failure_steps(); self.queue_dedicated_media_source_failure_steps(can_gc);
return; return;
} }
// Step 9.attr.3. // Step 9.attr.3.
@ -834,20 +835,20 @@ impl HTMLMediaElement {
Ok(url) => url, Ok(url) => url,
Err(_) => { Err(_) => {
source.upcast::<EventTarget>().fire_event(atom!("error")); source.upcast::<EventTarget>().fire_event(atom!("error"));
self.queue_dedicated_media_source_failure_steps(); self.queue_dedicated_media_source_failure_steps(can_gc);
return; return;
}, },
}; };
// Step 9.attr.8. // 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() { if self.resource_url.borrow().is_none() && self.blob_url.borrow().is_none() {
eprintln!("Missing request url"); eprintln!("Missing request url");
self.queue_dedicated_media_source_failure_steps(); self.queue_dedicated_media_source_failure_steps(can_gc);
return; return;
} }
@ -919,10 +920,10 @@ impl HTMLMediaElement {
} }
// https://html.spec.whatwg.org/multipage/#concept-media-load-resource // https://html.spec.whatwg.org/multipage/#concept-media-load-resource
fn resource_fetch_algorithm(&self, resource: Resource) { fn resource_fetch_algorithm(&self, resource: Resource, can_gc: CanGc) {
if let Err(e) = self.setup_media_player(&resource) { if let Err(e) = self.setup_media_player(&resource, CanGc::note()) {
eprintln!("Setup media player error {:?}", e); eprintln!("Setup media player error {:?}", e);
self.queue_dedicated_media_source_failure_steps(); self.queue_dedicated_media_source_failure_steps(CanGc::note());
return; return;
} }
@ -955,7 +956,7 @@ impl HTMLMediaElement {
.media_element_task_source() .media_element_task_source()
.queue( .queue(
task!(set_media_delay_load_event_flag_to_false: move || { 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(), window.upcast(),
) )
@ -974,7 +975,7 @@ impl HTMLMediaElement {
// Step 4.remote.2. // Step 4.remote.2.
*self.resource_url.borrow_mut() = Some(url); *self.resource_url.borrow_mut() = Some(url);
self.fetch_request(None, None); self.fetch_request(None, None, can_gc);
}, },
Resource::Object => { Resource::Object => {
if let Some(ref src_object) = *self.src_object.borrow() { if let Some(ref src_object) = *self.src_object.borrow() {
@ -983,7 +984,7 @@ impl HTMLMediaElement {
let blob_url = URL::CreateObjectURL(&self.global(), blob); let blob_url = URL::CreateObjectURL(&self.global(), blob);
*self.blob_url.borrow_mut() = *self.blob_url.borrow_mut() =
Some(ServoUrl::parse(&blob_url).expect("infallible")); Some(ServoUrl::parse(&blob_url).expect("infallible"));
self.fetch_request(None, None); self.fetch_request(None, None, can_gc);
}, },
SrcObject::MediaStream(ref stream) => { SrcObject::MediaStream(ref stream) => {
let tracks = &*stream.get_tracks(); let tracks = &*stream.get_tracks();
@ -998,7 +999,7 @@ impl HTMLMediaElement {
.set_stream(&track.id(), pos == tracks.len() - 1) .set_stream(&track.id(), pos == tracks.len() - 1)
.is_err() .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]. /// Queues a task to run the [dedicated media source failure steps][steps].
/// ///
/// [steps]: https://html.spec.whatwg.org/multipage/#dedicated-media-source-failure-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 window = window_from_node(self);
let this = Trusted::new(self); let this = Trusted::new(self);
let generation_id = self.generation_id.get(); let generation_id = self.generation_id.get();
@ -1056,7 +1057,7 @@ impl HTMLMediaElement {
}); });
// Step 7. // Step 7.
this.delay_load_event(false); this.delay_load_event(false, can_gc);
}), }),
window.upcast(), window.upcast(),
); );
@ -1104,7 +1105,7 @@ impl HTMLMediaElement {
} }
// https://html.spec.whatwg.org/multipage/#media-element-load-algorithm // 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 // Reset the flag that signals whether loadeddata was ever fired for
// this invokation of the load algorithm. // this invokation of the load algorithm.
self.fired_loadeddata_event.set(false); self.fired_loadeddata_event.set(false);
@ -1145,7 +1146,7 @@ impl HTMLMediaElement {
// Step 6.5. // Step 6.5.
if self.ready_state.get() != ReadyState::HaveNothing { if self.ready_state.get() != ReadyState::HaveNothing {
self.change_ready_state(ReadyState::HaveNothing); self.change_ready_state(ReadyState::HaveNothing, can_gc);
} }
// Step 6.6. // Step 6.6.
@ -1185,7 +1186,7 @@ impl HTMLMediaElement {
self.autoplaying.set(true); self.autoplaying.set(true);
// Step 9. // Step 9.
self.invoke_resource_selection_algorithm(); self.invoke_resource_selection_algorithm(CanGc::note());
// Step 10. // Step 10.
// FIXME(nox): Stop playback of any previously running media resource. // FIXME(nox): Stop playback of any previously running media resource.
@ -1245,14 +1246,14 @@ impl HTMLMediaElement {
/// Handles insertion of `source` children. /// Handles insertion of `source` children.
/// ///
/// <https://html.spec.whatwg.org/multipage/#the-source-element:nodes-are-inserted> /// <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")) { if self.upcast::<Element>().has_attribute(&local_name!("src")) {
return; return;
} }
if self.network_state.get() != NetworkState::Empty { if self.network_state.get() != NetworkState::Empty {
return; return;
} }
self.media_element_load_algorithm(); self.media_element_load_algorithm(can_gc);
} }
// https://html.spec.whatwg.org/multipage/#dom-media-seek // 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 { let stream_type = match *resource {
Resource::Object => { Resource::Object => {
if let Some(ref src_object) = *self.src_object.borrow() { if let Some(ref src_object) = *self.src_object.borrow() {
@ -1402,7 +1403,7 @@ impl HTMLMediaElement {
let this = trusted_node.clone(); let this = trusted_node.clone();
if let Err(err) = task_source.queue_with_canceller( if let Err(err) = task_source.queue_with_canceller(
task!(handle_player_event: move || { task!(handle_player_event: move || {
this.root().handle_player_event(&event); this.root().handle_player_event(&event, CanGc::note());
}), }),
&canceller, &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 { match *event {
PlayerEvent::EndOfStream => { PlayerEvent::EndOfStream => {
// https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list // 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 // => "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" // an unsupported format, or can otherwise not be rendered at all"
if self.ready_state.get() < ReadyState::HaveMetadata { if self.ready_state.get() < ReadyState::HaveMetadata {
self.queue_dedicated_media_source_failure_steps(); self.queue_dedicated_media_source_failure_steps(can_gc);
} else { } else {
// https://html.spec.whatwg.org/multipage/#reaches-the-end // https://html.spec.whatwg.org/multipage/#reaches-the-end
match self.direction_of_playback() { match self.direction_of_playback() {
@ -1548,7 +1549,7 @@ impl HTMLMediaElement {
); );
// https://html.spec.whatwg.org/multipage/#dom-media-have_current_data // 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); self.network_state.set(NetworkState::Idle);
// 4. Set the element's delaying-the-load-event flag to false. This stops delaying the load event. // 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. // 5. Fire an event named error at the media element.
self.upcast::<EventTarget>().fire_event(atom!("error")); self.upcast::<EventTarget>().fire_event(atom!("error"));
@ -1752,7 +1753,7 @@ impl HTMLMediaElement {
} }
// Step 6. // Step 6.
self.change_ready_state(ReadyState::HaveMetadata); self.change_ready_state(ReadyState::HaveMetadata, can_gc);
// Step 7. // Step 7.
let mut jumped = false; let mut jumped = false;
@ -1822,7 +1823,7 @@ impl HTMLMediaElement {
} }
}, },
PlayerEvent::EnoughData => { 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 // 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 // bytes, so we cancel the ongoing fetch request iff we are able
@ -1855,7 +1856,7 @@ impl HTMLMediaElement {
)); ));
}, },
PlayerEvent::SeekData(p, ref seek_lock) => { 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(_) => { PlayerEvent::SeekDone(_) => {
// Continuation of // Continuation of
@ -1874,7 +1875,7 @@ impl HTMLMediaElement {
PlaybackState::Paused => { PlaybackState::Paused => {
media_session_playback_state = MediaSessionPlaybackState::Paused; media_session_playback_state = MediaSessionPlaybackState::Paused;
if self.ready_state.get() == ReadyState::HaveMetadata { if self.ready_state.get() == ReadyState::HaveMetadata {
self.change_ready_state(ReadyState::HaveEnoughData); self.change_ready_state(ReadyState::HaveEnoughData, can_gc);
} }
}, },
PlaybackState::Playing => { PlaybackState::Playing => {
@ -1984,13 +1985,13 @@ impl HTMLMediaElement {
/// selected by the servo-media Player instance. However, in some cases, like /// selected by the servo-media Player instance. However, in some cases, like
/// the WebAudio MediaElementAudioSourceNode, we need to set a custom audio /// the WebAudio MediaElementAudioSourceNode, we need to set a custom audio
/// renderer. /// 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); *self.audio_renderer.borrow_mut() = Some(audio_renderer);
if let Some(ref player) = *self.player.borrow() { if let Some(ref player) = *self.player.borrow() {
if let Err(e) = player.lock().unwrap().stop() { if let Err(e) = player.lock().unwrap().stop() {
eprintln!("Could not stop player {:?}", e); 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 // 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.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 // 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 // https://html.spec.whatwg.org/multipage/#dom-media-load
fn Load(&self) { fn Load(&self, can_gc: CanGc) {
self.media_element_load_algorithm(); self.media_element_load_algorithm(can_gc);
} }
// https://html.spec.whatwg.org/multipage/#dom-navigator-canplaytype // 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 // 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); let promise = Promise::new_in_current_realm(comp);
// Step 1. // Step 1.
// FIXME(nox): Reject promise if not allowed to play. // FIXME(nox): Reject promise if not allowed to play.
@ -2197,7 +2198,7 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
// Step 4. // Step 4.
if self.network_state.get() == NetworkState::Empty { if self.network_state.get() == NetworkState::Empty {
self.invoke_resource_selection_algorithm(); self.invoke_resource_selection_algorithm(can_gc);
} }
// Step 5. // Step 5.
@ -2267,10 +2268,10 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
} }
// https://html.spec.whatwg.org/multipage/#dom-media-pause // https://html.spec.whatwg.org/multipage/#dom-media-pause
fn Pause(&self) { fn Pause(&self, can_gc: CanGc) {
// Step 1 // Step 1
if self.network_state.get() == NetworkState::Empty { if self.network_state.get() == NetworkState::Empty {
self.invoke_resource_selection_algorithm(); self.invoke_resource_selection_algorithm(can_gc);
} }
// Step 2 // Step 2
@ -2489,7 +2490,7 @@ impl VirtualMethods for HTMLMediaElement {
if mutation.new_value(attr).is_none() { if mutation.new_value(attr).is_none() {
return; return;
} }
self.media_element_load_algorithm(); self.media_element_load_algorithm(CanGc::note());
}, },
local_name!("controls") => { local_name!("controls") => {
if mutation.new_value(attr).is_some() { if mutation.new_value(attr).is_some() {
@ -2552,7 +2553,7 @@ pub enum MediaElementMicrotask {
} }
impl MicrotaskRunnable for MediaElementMicrotask { impl MicrotaskRunnable for MediaElementMicrotask {
fn handler(&self) { fn handler(&self, can_gc: CanGc) {
match self { match self {
&MediaElementMicrotask::ResourceSelectionTask { &MediaElementMicrotask::ResourceSelectionTask {
ref elem, ref elem,
@ -2560,7 +2561,7 @@ impl MicrotaskRunnable for MediaElementMicrotask {
ref base_url, ref base_url,
} => { } => {
if generation_id == elem.generation_id.get() { 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 } => { 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() { if let Some(ref mut current_fetch_context) = *elem.current_fetch_context.borrow_mut() {
current_fetch_context.cancel(CancelReason::Error); 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); elem.network_state.set(NetworkState::Idle);
// Step 4. // Step 4.
elem.delay_load_event(false); elem.delay_load_event(false, CanGc::note());
// Step 5 // Step 5
elem.upcast::<EventTarget>().fire_event(atom!("error")); elem.upcast::<EventTarget>().fire_event(atom!("error"));
} else { } else {
// => "If the media data cannot be fetched at all..." // => "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());
} }
} }

View file

@ -87,7 +87,7 @@ impl HTMLOptionElement {
pub fn Option( pub fn Option(
window: &Window, window: &Window,
proto: Option<HandleObject>, proto: Option<HandleObject>,
_can_gc: CanGc, can_gc: CanGc,
text: DOMString, text: DOMString,
value: Option<DOMString>, value: Option<DOMString>,
default_selected: bool, default_selected: bool,
@ -100,6 +100,7 @@ impl HTMLOptionElement {
ElementCreator::ScriptCreated, ElementCreator::ScriptCreated,
CustomElementCreationMode::Synchronous, CustomElementCreationMode::Synchronous,
proto, proto,
can_gc,
); );
let option = DomRoot::downcast::<HTMLOptionElement>(element).unwrap(); let option = DomRoot::downcast::<HTMLOptionElement>(element).unwrap();

View file

@ -66,6 +66,7 @@ use crate::realms::enter_realm;
use crate::script_module::{ use crate::script_module::{
fetch_external_module_script, fetch_inline_module_script, ModuleOwner, ScriptFetchOptions, fetch_external_module_script, fetch_inline_module_script, ModuleOwner, ScriptFetchOptions,
}; };
use crate::script_runtime::CanGc;
use crate::task::TaskCanceller; use crate::task::TaskCanceller;
use crate::task_source::dom_manipulation::DOMManipulationTaskSource; use crate::task_source::dom_manipulation::DOMManipulationTaskSource;
use crate::task_source::{TaskSource, TaskSourceName}; use crate::task_source::{TaskSource, TaskSourceName};
@ -304,6 +305,7 @@ fn finish_fetching_a_classic_script(
script_kind: ExternalScriptKind, script_kind: ExternalScriptKind,
url: ServoUrl, url: ServoUrl,
load: ScriptResult, load: ScriptResult,
can_gc: CanGc,
) { ) {
// Step 11, Asynchronously complete this algorithm with script, // Step 11, Asynchronously complete this algorithm with script,
// which refers to step 26.6 "When the chosen algorithm asynchronously completes", // 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::AsapInOrder => document.asap_in_order_script_loaded(elem, load),
ExternalScriptKind::Deferred => document.deferred_script_loaded(elem, load), ExternalScriptKind::Deferred => document.deferred_script_loaded(elem, load),
ExternalScriptKind::ParsingBlocking => { 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>>; pub type ScriptResult = Result<ScriptOrigin, NoTrace<NetworkError>>;
@ -397,6 +399,7 @@ impl FetchResponseListener for ClassicContext {
self.kind, self.kind,
self.url.clone(), self.url.clone(),
Err(NoTrace(err.clone())), Err(NoTrace(err.clone())),
CanGc::note(),
); );
return; return;
}, },
@ -457,7 +460,13 @@ impl FetchResponseListener for ClassicContext {
self.fetch_options.clone(), self.fetch_options.clone(),
ScriptType::Classic, 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(),
);
//} //}
} }

View file

@ -19,6 +19,7 @@ use crate::dom::htmlimageelement::HTMLImageElement;
use crate::dom::htmlmediaelement::HTMLMediaElement; use crate::dom::htmlmediaelement::HTMLMediaElement;
use crate::dom::node::{BindContext, Node, UnbindContext}; use crate::dom::node::{BindContext, Node, UnbindContext};
use crate::dom::virtualmethods::VirtualMethods; use crate::dom::virtualmethods::VirtualMethods;
use crate::script_runtime::CanGc;
#[dom_struct] #[dom_struct]
pub struct HTMLSourceElement { pub struct HTMLSourceElement {
@ -54,10 +55,11 @@ impl HTMLSourceElement {
fn iterate_next_html_image_element_siblings( fn iterate_next_html_image_element_siblings(
next_siblings_iterator: impl Iterator<Item = Root<Dom<Node>>>, next_siblings_iterator: impl Iterator<Item = Root<Dom<Node>>>,
_can_gc: CanGc,
) { ) {
for next_sibling in next_siblings_iterator { for next_sibling in next_siblings_iterator {
if let Some(html_image_element_sibling) = next_sibling.downcast::<HTMLImageElement>() { 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!("media") |
&local_name!("type") => { &local_name!("type") => {
let next_sibling_iterator = self.upcast::<Node>().following_siblings(); 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); self.super_type().unwrap().bind_to_tree(context);
let parent = self.upcast::<Node>().GetParentNode().unwrap(); let parent = self.upcast::<Node>().GetParentNode().unwrap();
if let Some(media) = parent.downcast::<HTMLMediaElement>() { 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(); 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) { fn unbind_from_tree(&self, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(context); self.super_type().unwrap().unbind_from_tree(context);
if let Some(next_sibling) = context.next_sibling { if let Some(next_sibling) = context.next_sibling {
let next_sibling_iterator = next_sibling.inclusively_following_siblings(); 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(),
);
} }
} }
} }

View file

@ -16,6 +16,7 @@ use crate::dom::documentfragment::DocumentFragment;
use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlelement::HTMLElement;
use crate::dom::node::{document_from_node, CloneChildrenFlag, Node}; use crate::dom::node::{document_from_node, CloneChildrenFlag, Node};
use crate::dom::virtualmethods::VirtualMethods; use crate::dom::virtualmethods::VirtualMethods;
use crate::script_runtime::CanGc;
#[dom_struct] #[dom_struct]
pub struct HTMLTemplateElement { pub struct HTMLTemplateElement {
@ -59,10 +60,10 @@ impl HTMLTemplateElement {
impl HTMLTemplateElementMethods for HTMLTemplateElement { impl HTMLTemplateElementMethods for HTMLTemplateElement {
/// <https://html.spec.whatwg.org/multipage/#dom-template-content> /// <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(|| { self.contents.or_init(|| {
let doc = document_from_node(self); let doc = document_from_node(self);
doc.appropriate_template_contents_owner_document() doc.appropriate_template_contents_owner_document(can_gc)
.CreateDocumentFragment() .CreateDocumentFragment()
}) })
} }
@ -77,9 +78,10 @@ impl VirtualMethods for HTMLTemplateElement {
fn adopting_steps(&self, old_doc: &Document) { fn adopting_steps(&self, old_doc: &Document) {
self.super_type().unwrap().adopting_steps(old_doc); self.super_type().unwrap().adopting_steps(old_doc);
// Step 1. // 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. // 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> /// <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(); let copy = copy.downcast::<HTMLTemplateElement>().unwrap();
// Steps 2-3. // 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(); 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( let copy_child = Node::clone(
&child, &child,
Some(&copy_contents_doc), Some(&copy_contents_doc),
CloneChildrenFlag::CloneChildren, CloneChildrenFlag::CloneChildren,
CanGc::note(),
); );
copy_contents.AppendChild(&copy_child).unwrap(); copy_contents.AppendChild(&copy_child).unwrap();
} }

View file

@ -42,6 +42,7 @@ use crate::dom::virtualmethods::VirtualMethods;
use crate::fetch::FetchCanceller; use crate::fetch::FetchCanceller;
use crate::image_listener::{generate_cache_listener_for_element, ImageCacheListener}; use crate::image_listener::{generate_cache_listener_for_element, ImageCacheListener};
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
use crate::script_runtime::CanGc;
const DEFAULT_WIDTH: u32 = 300; const DEFAULT_WIDTH: u32 = 300;
const DEFAULT_HEIGHT: u32 = 150; const DEFAULT_HEIGHT: u32 = 150;
@ -137,7 +138,7 @@ impl HTMLVideoElement {
} }
/// <https://html.spec.whatwg.org/multipage/#poster-frame> /// <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. // Step 1.
let cancel_receiver = self.poster_frame_canceller.borrow_mut().initialize(); let cancel_receiver = self.poster_frame_canceller.borrow_mut().initialize();
self.generation_id.set(self.generation_id.get() + 1); self.generation_id.set(self.generation_id.get() + 1);
@ -176,7 +177,7 @@ impl HTMLVideoElement {
self.process_image_response(ImageResponse::Loaded(image, url)); self.process_image_response(ImageResponse::Loaded(image, url));
}, },
ImageCacheResult::ReadyForRequest(id) => { 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, poster_url: ServoUrl,
id: PendingImageId, id: PendingImageId,
cancel_receiver: ipc::IpcReceiver<()>, cancel_receiver: ipc::IpcReceiver<()>,
can_gc: CanGc,
) { ) {
// Continuation of step 4. // Continuation of step 4.
let document = document_from_node(self); 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) // (which triggers no media load algorithm unless a explicit call to .load() is done)
// will block the document's load event forever. // will block the document's load event forever.
let mut blocker = self.load_blocker.borrow_mut(); let mut blocker = self.load_blocker.borrow_mut();
LoadBlocker::terminate(&mut blocker); LoadBlocker::terminate(&mut blocker, can_gc);
*blocker = Some(LoadBlocker::new( *blocker = Some(LoadBlocker::new(
&document_from_node(self), &document_from_node(self),
LoadType::Image(poster_url.clone()), LoadType::Image(poster_url.clone()),
@ -280,7 +282,7 @@ impl VirtualMethods for HTMLVideoElement {
if let Some(new_value) = mutation.new_value(attr) { if let Some(new_value) = mutation.new_value(attr) {
if attr.local_name() == &local_name!("poster") { 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) => { ImageResponse::Loaded(image, url) => {
debug!("Loaded poster image for video element: {:?}", url); debug!("Loaded poster image for video element: {:?}", url);
self.htmlmediaelement.process_poster_image_loaded(image); 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(..) => {}, ImageResponse::MetadataLoaded(..) => {},
// The image cache may have loaded a placeholder for an invalid poster url // The image cache may have loaded a placeholder for an invalid poster url
ImageResponse::PlaceholderLoaded(..) | ImageResponse::None => { ImageResponse::PlaceholderLoaded(..) | ImageResponse::None => {
// A failed load should unblock the document load. // 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());
}, },
} }
} }

View file

@ -32,6 +32,7 @@ impl MediaElementAudioSourceNode {
fn new_inherited( fn new_inherited(
context: &AudioContext, context: &AudioContext,
media_element: &HTMLMediaElement, media_element: &HTMLMediaElement,
can_gc: CanGc,
) -> Fallible<MediaElementAudioSourceNode> { ) -> Fallible<MediaElementAudioSourceNode> {
let node = AudioNode::new_inherited( let node = AudioNode::new_inherited(
AudioNodeInit::MediaElementSourceNode, AudioNodeInit::MediaElementSourceNode,
@ -45,7 +46,7 @@ impl MediaElementAudioSourceNode {
MediaElementSourceNodeMessage::GetAudioRenderer(sender), MediaElementSourceNodeMessage::GetAudioRenderer(sender),
)); ));
let audio_renderer = receiver.recv().unwrap(); 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); let media_element = Dom::from_ref(media_element);
Ok(MediaElementAudioSourceNode { Ok(MediaElementAudioSourceNode {
node, node,
@ -69,12 +70,12 @@ impl MediaElementAudioSourceNode {
media_element: &HTMLMediaElement, media_element: &HTMLMediaElement,
can_gc: CanGc, can_gc: CanGc,
) -> Fallible<DomRoot<MediaElementAudioSourceNode>> { ) -> 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( Ok(reflect_dom_object_with_proto(
Box::new(node), Box::new(node),
window, window,
proto, proto,
can_gc, CanGc::note(),
)) ))
} }

View file

@ -28,6 +28,7 @@ use crate::dom::htmlmediaelement::HTMLMediaElement;
use crate::dom::mediametadata::MediaMetadata; use crate::dom::mediametadata::MediaMetadata;
use crate::dom::window::Window; use crate::dom::window::Window;
use crate::realms::{enter_realm, InRealm}; use crate::realms::{enter_realm, InRealm};
use crate::script_runtime::CanGc;
#[dom_struct] #[dom_struct]
pub struct MediaSession { pub struct MediaSession {
@ -67,7 +68,7 @@ impl MediaSession {
self.media_instance.set(Some(media_instance)); 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); debug!("Handle media session action {:?}", action);
if let Some(handler) = self.action_handlers.borrow().get(&action) { if let Some(handler) = self.action_handlers.borrow().get(&action) {
@ -82,10 +83,10 @@ impl MediaSession {
match action { match action {
MediaSessionActionType::Play => { MediaSessionActionType::Play => {
let realm = enter_realm(self); let realm = enter_realm(self);
media.Play(InRealm::Entered(&realm)); media.Play(InRealm::Entered(&realm), can_gc);
}, },
MediaSessionActionType::Pause => { MediaSessionActionType::Pause => {
media.Pause(); media.Pause(can_gc);
}, },
MediaSessionActionType::SeekBackward => {}, MediaSessionActionType::SeekBackward => {},
MediaSessionActionType::SeekForward => {}, MediaSessionActionType::SeekForward => {},

View file

@ -2240,6 +2240,7 @@ impl Node {
node: &Node, node: &Node,
maybe_doc: Option<&Document>, maybe_doc: Option<&Document>,
clone_children: CloneChildrenFlag, clone_children: CloneChildrenFlag,
can_gc: CanGc,
) -> DomRoot<Node> { ) -> DomRoot<Node> {
// Step 1. // Step 1.
let document = match maybe_doc { let document = match maybe_doc {
@ -2306,6 +2307,7 @@ impl Node {
None, None,
document.status_code(), document.status_code(),
Default::default(), Default::default(),
CanGc::note(),
); );
DomRoot::upcast::<Node>(document) DomRoot::upcast::<Node>(document)
}, },
@ -2323,6 +2325,7 @@ impl Node {
ElementCreator::ScriptCreated, ElementCreator::ScriptCreated,
CustomElementCreationMode::Asynchronous, CustomElementCreationMode::Asynchronous,
None, None,
can_gc,
); );
DomRoot::upcast::<Node>(element) DomRoot::upcast::<Node>(element)
}, },
@ -2366,7 +2369,8 @@ impl Node {
// Step 6. // Step 6.
if clone_children == CloneChildrenFlag::CloneChildren { if clone_children == CloneChildrenFlag::CloneChildren {
for child in node.children() { 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, &copy, None); let _inserted_node = Node::pre_insert(&child_copy, &copy, None);
} }
} }
@ -2816,7 +2820,7 @@ impl NodeMethods for Node {
} }
/// <https://dom.spec.whatwg.org/#dom-node-clonenode> /// <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>() { if deep && self.is::<ShadowRoot>() {
return Err(Error::NotSupported); return Err(Error::NotSupported);
} }
@ -2828,6 +2832,7 @@ impl NodeMethods for Node {
} else { } else {
CloneChildrenFlag::DoNotCloneChildren CloneChildrenFlag::DoNotCloneChildren
}, },
can_gc,
)) ))
} }

View file

@ -87,6 +87,7 @@ impl Range {
start_offset: u32, start_offset: u32,
end_container: &Node, end_container: &Node,
end_offset: u32, end_offset: u32,
can_gc: CanGc,
) -> DomRoot<Range> { ) -> DomRoot<Range> {
Self::new_with_proto( Self::new_with_proto(
document, document,
@ -95,7 +96,7 @@ impl Range {
start_offset, start_offset,
end_container, end_container,
end_offset, end_offset,
CanGc::note(), can_gc,
) )
} }
@ -482,7 +483,7 @@ impl RangeMethods for Range {
} }
/// <https://dom.spec.whatwg.org/#dom-range-clonerange> /// <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 start_node = self.start_container();
let owner_doc = start_node.owner_doc(); let owner_doc = start_node.owner_doc();
Range::new( Range::new(
@ -491,6 +492,7 @@ impl RangeMethods for Range {
self.start_offset(), self.start_offset(),
&self.end_container(), &self.end_container(),
self.end_offset(), 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/#dom-range-clonecontents>
/// <https://dom.spec.whatwg.org/#concept-range-clone> /// <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. // Step 3.
let start_node = self.start_container(); let start_node = self.start_container();
let start_offset = self.start_offset(); let start_offset = self.start_offset();
@ -598,7 +600,7 @@ impl RangeMethods for Range {
fragment.upcast::<Node>().AppendChild(&clone)?; fragment.upcast::<Node>().AppendChild(&clone)?;
} else { } else {
// Step 14.1. // Step 14.1.
let clone = child.CloneNode(/* deep */ false)?; let clone = child.CloneNode(/* deep */ false, CanGc::note())?;
// Step 14.2. // Step 14.2.
fragment.upcast::<Node>().AppendChild(&clone)?; fragment.upcast::<Node>().AppendChild(&clone)?;
// Step 14.3. // Step 14.3.
@ -608,9 +610,10 @@ impl RangeMethods for Range {
start_offset, start_offset,
&child, &child,
child.len(), child.len(),
can_gc,
); );
// Step 14.4. // Step 14.4.
let subfragment = subrange.CloneContents()?; let subfragment = subrange.CloneContents(CanGc::note())?;
// Step 14.5. // Step 14.5.
clone.AppendChild(subfragment.upcast())?; clone.AppendChild(subfragment.upcast())?;
} }
@ -619,7 +622,7 @@ impl RangeMethods for Range {
// Step 15. // Step 15.
for child in contained_children { for child in contained_children {
// Step 15.1. // Step 15.1.
let clone = child.CloneNode(/* deep */ true)?; let clone = child.CloneNode(/* deep */ true, CanGc::note())?;
// Step 15.2. // Step 15.2.
fragment.upcast::<Node>().AppendChild(&clone)?; fragment.upcast::<Node>().AppendChild(&clone)?;
} }
@ -635,13 +638,20 @@ impl RangeMethods for Range {
fragment.upcast::<Node>().AppendChild(&clone)?; fragment.upcast::<Node>().AppendChild(&clone)?;
} else { } else {
// Step 17.1. // Step 17.1.
let clone = child.CloneNode(/* deep */ false)?; let clone = child.CloneNode(/* deep */ false, CanGc::note())?;
// Step 17.2. // Step 17.2.
fragment.upcast::<Node>().AppendChild(&clone)?; fragment.upcast::<Node>().AppendChild(&clone)?;
// Step 17.3. // 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. // Step 17.4.
let subfragment = subrange.CloneContents()?; let subfragment = subrange.CloneContents(CanGc::note())?;
// Step 17.5. // Step 17.5.
clone.AppendChild(subfragment.upcast())?; 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/#dom-range-extractcontents>
/// <https://dom.spec.whatwg.org/#concept-range-extract> /// <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. // Step 3.
let start_node = self.start_container(); let start_node = self.start_container();
let start_offset = self.start_offset(); let start_offset = self.start_offset();
@ -671,7 +681,7 @@ impl RangeMethods for Range {
if end_node == start_node { if end_node == start_node {
if let Some(end_data) = end_node.downcast::<CharacterData>() { if let Some(end_data) = end_node.downcast::<CharacterData>() {
// Step 4.1. // Step 4.1.
let clone = end_node.CloneNode(/* deep */ true)?; let clone = end_node.CloneNode(/* deep */ true, CanGc::note())?;
// Step 4.2. // Step 4.2.
let text = end_data.SubstringData(start_offset, end_offset - start_offset); let text = end_data.SubstringData(start_offset, end_offset - start_offset);
clone clone
@ -712,7 +722,7 @@ impl RangeMethods for Range {
if let Some(start_data) = child.downcast::<CharacterData>() { if let Some(start_data) = child.downcast::<CharacterData>() {
assert!(child == start_node); assert!(child == start_node);
// Step 15.1. // Step 15.1.
let clone = start_node.CloneNode(/* deep */ true)?; let clone = start_node.CloneNode(/* deep */ true, CanGc::note())?;
// Step 15.2. // Step 15.2.
let text = start_data.SubstringData(start_offset, start_node.len() - start_offset); let text = start_data.SubstringData(start_offset, start_node.len() - start_offset);
clone clone
@ -729,7 +739,7 @@ impl RangeMethods for Range {
)?; )?;
} else { } else {
// Step 16.1. // Step 16.1.
let clone = child.CloneNode(/* deep */ false)?; let clone = child.CloneNode(/* deep */ false, CanGc::note())?;
// Step 16.2. // Step 16.2.
fragment.upcast::<Node>().AppendChild(&clone)?; fragment.upcast::<Node>().AppendChild(&clone)?;
// Step 16.3. // Step 16.3.
@ -739,9 +749,10 @@ impl RangeMethods for Range {
start_offset, start_offset,
&child, &child,
child.len(), child.len(),
can_gc,
); );
// Step 16.4. // Step 16.4.
let subfragment = subrange.ExtractContents()?; let subfragment = subrange.ExtractContents(CanGc::note())?;
// Step 16.5. // Step 16.5.
clone.AppendChild(subfragment.upcast())?; clone.AppendChild(subfragment.upcast())?;
} }
@ -756,7 +767,7 @@ impl RangeMethods for Range {
if let Some(end_data) = child.downcast::<CharacterData>() { if let Some(end_data) = child.downcast::<CharacterData>() {
assert!(child == end_node); assert!(child == end_node);
// Step 18.1. // Step 18.1.
let clone = end_node.CloneNode(/* deep */ true)?; let clone = end_node.CloneNode(/* deep */ true, CanGc::note())?;
// Step 18.2. // Step 18.2.
let text = end_data.SubstringData(0, end_offset); let text = end_data.SubstringData(0, end_offset);
clone clone
@ -769,13 +780,20 @@ impl RangeMethods for Range {
end_data.ReplaceData(0, end_offset, DOMString::new())?; end_data.ReplaceData(0, end_offset, DOMString::new())?;
} else { } else {
// Step 19.1. // Step 19.1.
let clone = child.CloneNode(/* deep */ false)?; let clone = child.CloneNode(/* deep */ false, CanGc::note())?;
// Step 19.2. // Step 19.2.
fragment.upcast::<Node>().AppendChild(&clone)?; fragment.upcast::<Node>().AppendChild(&clone)?;
// Step 19.3. // 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. // Step 19.4.
let subfragment = subrange.ExtractContents()?; let subfragment = subrange.ExtractContents(CanGc::note())?;
// Step 19.5. // Step 19.5.
clone.AppendChild(subfragment.upcast())?; clone.AppendChild(subfragment.upcast())?;
} }
@ -964,7 +982,7 @@ impl RangeMethods for Range {
} }
/// <https://dom.spec.whatwg.org/#dom-range-surroundcontents> /// <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. // Step 1.
let start = self.start_container(); let start = self.start_container();
let end = self.end_container(); let end = self.end_container();
@ -989,7 +1007,7 @@ impl RangeMethods for Range {
} }
// Step 3. // Step 3.
let fragment = self.ExtractContents()?; let fragment = self.ExtractContents(can_gc)?;
// Step 4. // Step 4.
Node::replace_all(None, new_parent); 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> /// <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. // Step 1.
let node = self.start_container(); let node = self.start_container();
let owner_doc = node.owner_doc(); 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()); let element = Element::fragment_parsing_context(&owner_doc, element.as_deref());
// Step 3. // Step 3.
let fragment_node = element.parse_fragment(fragment)?; let fragment_node = element.parse_fragment(fragment, can_gc)?;
// Step 4. // Step 4.
for node in fragment_node for node in fragment_node

View file

@ -19,6 +19,7 @@ use crate::dom::document::Document;
use crate::dom::eventtarget::EventTarget; use crate::dom::eventtarget::EventTarget;
use crate::dom::node::{window_from_node, Node}; use crate::dom::node::{window_from_node, Node};
use crate::dom::range::Range; use crate::dom::range::Range;
use crate::script_runtime::CanGc;
use crate::task_source::TaskSource; use crate::task_source::TaskSource;
#[derive(Clone, Copy, JSTraceable, MallocSizeOf)] #[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
@ -241,7 +242,7 @@ impl SelectionMethods for Selection {
} }
// https://w3c.github.io/selection-api/#dom-selection-collapse // 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 let Some(node) = node {
if node.is_doctype() { if node.is_doctype() {
// w3c/selection-api#118 // w3c/selection-api#118
@ -258,7 +259,7 @@ impl SelectionMethods for Selection {
} }
// Steps 4-5 // 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 // Step 6
self.set_range(&range); self.set_range(&range);
@ -276,23 +277,27 @@ impl SelectionMethods for Selection {
// TODO: When implementing actual selection UI, this may be the correct // TODO: When implementing actual selection UI, this may be the correct
// method to call as the start-of-selection action, after a // method to call as the start-of-selection action, after a
// selectstart event has fired and not been cancelled. // selectstart event has fired and not been cancelled.
fn SetPosition(&self, node: Option<&Node>, offset: u32) -> ErrorResult { fn SetPosition(&self, node: Option<&Node>, offset: u32, can_gc: CanGc) -> ErrorResult {
self.Collapse(node, offset) self.Collapse(node, offset, can_gc)
} }
// https://w3c.github.io/selection-api/#dom-selection-collapsetostart // 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() { 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 { } else {
Err(Error::InvalidState) Err(Error::InvalidState)
} }
} }
// https://w3c.github.io/selection-api/#dom-selection-collapsetoend // 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() { 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 { } else {
Err(Error::InvalidState) Err(Error::InvalidState)
} }
@ -301,7 +306,7 @@ impl SelectionMethods for Selection {
// https://w3c.github.io/selection-api/#dom-selection-extend // https://w3c.github.io/selection-api/#dom-selection-extend
// TODO: When implementing actual selection UI, this may be the correct // TODO: When implementing actual selection UI, this may be the correct
// method to call as the continue-selection action // 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) { if !self.is_same_root(node) {
// Step 1 // Step 1
return Ok(()); return Ok(());
@ -321,7 +326,14 @@ impl SelectionMethods for Selection {
// Step 4 // Step 4
if !self.is_same_root(&range.start_container()) { if !self.is_same_root(&range.start_container()) {
// Step 5, and its following 8 and 9 // 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); self.direction.set(Direction::Forwards);
} else { } else {
let old_anchor_node = &*self.GetAnchorNode().unwrap(); // has range, therefore has anchor node let old_anchor_node = &*self.GetAnchorNode().unwrap(); // has range, therefore has anchor node
@ -341,6 +353,7 @@ impl SelectionMethods for Selection {
old_anchor_offset, old_anchor_offset,
node, node,
offset, offset,
can_gc,
)); ));
self.direction.set(Direction::Forwards); self.direction.set(Direction::Forwards);
} else { } else {
@ -351,6 +364,7 @@ impl SelectionMethods for Selection {
offset, offset,
old_anchor_node, old_anchor_node,
old_anchor_offset, old_anchor_offset,
can_gc,
)); ));
self.direction.set(Direction::Backwards); self.direction.set(Direction::Backwards);
} }
@ -369,6 +383,7 @@ impl SelectionMethods for Selection {
anchor_offset: u32, anchor_offset: u32,
focus_node: &Node, focus_node: &Node,
focus_offset: u32, focus_offset: u32,
can_gc: CanGc,
) -> ErrorResult { ) -> ErrorResult {
// Step 1 // Step 1
if anchor_node.is_doctype() || focus_node.is_doctype() { if anchor_node.is_doctype() || focus_node.is_doctype() {
@ -400,6 +415,7 @@ impl SelectionMethods for Selection {
focus_offset, focus_offset,
anchor_node, anchor_node,
anchor_offset, anchor_offset,
can_gc,
)); ));
self.direction.set(Direction::Backwards); self.direction.set(Direction::Backwards);
} else { } else {
@ -409,6 +425,7 @@ impl SelectionMethods for Selection {
anchor_offset, anchor_offset,
focus_node, focus_node,
focus_offset, focus_offset,
can_gc,
)); ));
self.direction.set(Direction::Forwards); self.direction.set(Direction::Forwards);
} }
@ -416,7 +433,7 @@ impl SelectionMethods for Selection {
} }
// https://w3c.github.io/selection-api/#dom-selection-selectallchildren // 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() { if node.is_doctype() {
// w3c/selection-api#118 // w3c/selection-api#118
return Err(Error::InvalidNodeType); return Err(Error::InvalidNodeType);
@ -434,6 +451,7 @@ impl SelectionMethods for Selection {
0, 0,
node, node,
node.children_count(), node.children_count(),
can_gc,
)); ));
self.direction.set(Direction::Forwards); self.direction.set(Direction::Forwards);

View file

@ -45,7 +45,7 @@ use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::fetch::load_whole_resource; use crate::fetch::load_whole_resource;
use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; use crate::realms::{enter_realm, AlreadyInRealm, InRealm};
use crate::script_runtime::{ 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, Runtime, ScriptChan,
}; };
use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue}; use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
@ -295,6 +295,7 @@ impl ServiceWorkerGlobalScope {
control_receiver: Receiver<ServiceWorkerControlMsg>, control_receiver: Receiver<ServiceWorkerControlMsg>,
context_sender: Sender<ContextForRequestInterrupt>, context_sender: Sender<ContextForRequestInterrupt>,
closing: Arc<AtomicBool>, closing: Arc<AtomicBool>,
_can_gc: CanGc,
) -> JoinHandle<()> { ) -> JoinHandle<()> {
let ScopeThings { let ScopeThings {
script_url, script_url,
@ -398,7 +399,7 @@ impl ServiceWorkerGlobalScope {
// which happens after the closing flag is set to true, // which happens after the closing flag is set to true,
// or until the worker has run beyond its allocated time. // or until the worker has run beyond its allocated time.
while !scope.is_closing() && !global.has_timed_out() { while !scope.is_closing() && !global.has_timed_out() {
run_worker_event_loop(&*global, None); run_worker_event_loop(&*global, None, CanGc::note());
} }
}, },
reporter_name, reporter_name,

View file

@ -41,6 +41,7 @@ use crate::dom::node::Node;
use crate::dom::processinginstruction::ProcessingInstruction; use crate::dom::processinginstruction::ProcessingInstruction;
use crate::dom::servoparser::{create_element_for_token, ElementAttribute, ParsingAlgorithm}; use crate::dom::servoparser::{create_element_for_token, ElementAttribute, ParsingAlgorithm};
use crate::dom::virtualmethods::vtable_for; use crate::dom::virtualmethods::vtable_for;
use crate::script_runtime::CanGc;
type ParseNodeId = usize; type ParseNodeId = usize;
@ -283,7 +284,11 @@ impl Tokenizer {
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(); let mut send_tendrils = VecDeque::new();
while let Some(str) = input.pop_front() { while let Some(str) = input.pop_front() {
send_tendrils.push_back(SendTendril::from(str)); send_tendrils.push_back(SendTendril::from(str));
@ -303,7 +308,9 @@ impl Tokenizer {
.recv() .recv()
.expect("Unexpected channel panic in main thread.") .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::TokenizerResultDone { updated_input } => {
let buffer_queue = create_buffer_queue(updated_input); let buffer_queue = create_buffer_queue(updated_input);
input.replace_with(buffer_queue); 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 self.html_tokenizer_sender
.send(ToHtmlTokenizerMsg::End) .send(ToHtmlTokenizerMsg::End)
.unwrap(); .unwrap();
@ -333,7 +340,9 @@ impl Tokenizer {
.recv() .recv()
.expect("Unexpected channel panic in main thread.") .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::TokenizerResultDone { updated_input: _ } |
ToTokenizerMsg::TokenizerResultScript { ToTokenizerMsg::TokenizerResultScript {
script: _, 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 { let node = match node {
NodeOrText::Node(n) => { NodeOrText::Node(n) => {
HtmlNodeOrText::AppendNode(Dom::from_ref(&**self.get_node(&n.id))) HtmlNodeOrText::AppendNode(Dom::from_ref(&**self.get_node(&n.id)))
@ -376,10 +385,10 @@ impl Tokenizer {
.GetParentNode() .GetParentNode()
.expect("append_before_sibling called on node without parent"); .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 { let node = match node {
NodeOrText::Node(n) => { NodeOrText::Node(n) => {
HtmlNodeOrText::AppendNode(Dom::from_ref(&**self.get_node(&n.id))) HtmlNodeOrText::AppendNode(Dom::from_ref(&**self.get_node(&n.id)))
@ -388,7 +397,7 @@ impl Tokenizer {
}; };
let parent = &**self.get_node(&parent); 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 { fn has_parent_node(&self, node: ParseNodeId) -> bool {
@ -404,7 +413,7 @@ impl Tokenizer {
x.is_in_same_home_subtree(y) 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 = DomRoot::from_ref(&**self.get_node(&0));
let document = document let document = document
.downcast::<Document>() .downcast::<Document>()
@ -415,7 +424,7 @@ impl Tokenizer {
let template = target let template = target
.downcast::<HTMLTemplateElement>() .downcast::<HTMLTemplateElement>()
.expect("Tried to extract contents from non-template element while parsing"); .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 { ParseOperation::CreateElement {
node, node,
@ -433,6 +442,7 @@ impl Tokenizer {
&self.document, &self.document,
ElementCreator::ParserCreated(current_line), ElementCreator::ParserCreated(current_line),
ParsingAlgorithm::Normal, ParsingAlgorithm::Normal,
can_gc,
); );
self.insert_node(node, Dom::from_ref(element.upcast())); self.insert_node(node, Dom::from_ref(element.upcast()));
}, },
@ -441,10 +451,10 @@ impl Tokenizer {
self.insert_node(node, Dom::from_ref(comment.upcast())); self.insert_node(node, Dom::from_ref(comment.upcast()));
}, },
ParseOperation::AppendBeforeSibling { sibling, node } => { ParseOperation::AppendBeforeSibling { sibling, node } => {
self.append_before_sibling(sibling, node); self.append_before_sibling(sibling, node, can_gc);
}, },
ParseOperation::Append { parent, node } => { ParseOperation::Append { parent, node } => {
self.append(parent, node); self.append(parent, node, can_gc);
}, },
ParseOperation::AppendBasedOnParentNode { ParseOperation::AppendBasedOnParentNode {
element, element,
@ -452,9 +462,9 @@ impl Tokenizer {
node, node,
} => { } => {
if self.has_parent_node(element) { if self.has_parent_node(element) {
self.append_before_sibling(element, node); self.append_before_sibling(element, node, can_gc);
} else { } else {
self.append(prev_element, node); self.append(prev_element, node, can_gc);
} }
}, },
ParseOperation::AppendDoctypeToDocument { ParseOperation::AppendDoctypeToDocument {

View file

@ -30,6 +30,7 @@ use crate::dom::htmltemplateelement::HTMLTemplateElement;
use crate::dom::node::Node; use crate::dom::node::Node;
use crate::dom::processinginstruction::ProcessingInstruction; use crate::dom::processinginstruction::ProcessingInstruction;
use crate::dom::servoparser::{ParsingAlgorithm, Sink}; use crate::dom::servoparser::{ParsingAlgorithm, Sink};
use crate::script_runtime::CanGc;
#[derive(JSTraceable, MallocSizeOf)] #[derive(JSTraceable, MallocSizeOf)]
#[crown::unrooted_must_root_lint::must_root] #[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>() { 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(), None => n.rev_children(),
} }
} }

View file

@ -67,6 +67,7 @@ use crate::dom::text::Text;
use crate::dom::virtualmethods::vtable_for; use crate::dom::virtualmethods::vtable_for;
use crate::network_listener::PreInvoke; use crate::network_listener::PreInvoke;
use crate::realms::enter_realm; use crate::realms::enter_realm;
use crate::script_runtime::CanGc;
use crate::script_thread::ScriptThread; use crate::script_thread::ScriptThread;
mod async_html; mod async_html;
@ -150,7 +151,12 @@ impl ServoParser {
self.can_write() 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) { let parser = if pref!(dom.servoparser.async_html_tokenizer.enabled) {
ServoParser::new( ServoParser::new(
document, document,
@ -172,7 +178,7 @@ impl ServoParser {
// Set as the document's current parser and initialize with `input`, if given. // Set as the document's current parser and initialize with `input`, if given.
if let Some(input) = input { if let Some(input) = input {
parser.parse_complete_string_chunk(String::from(input)); parser.parse_complete_string_chunk(String::from(input), can_gc);
} else { } else {
parser.document.set_current_parser(Some(&parser)); parser.document.set_current_parser(Some(&parser));
} }
@ -182,6 +188,7 @@ impl ServoParser {
pub fn parse_html_fragment( pub fn parse_html_fragment(
context: &Element, context: &Element,
input: DOMString, input: DOMString,
can_gc: CanGc,
) -> impl Iterator<Item = DomRoot<Node>> { ) -> impl Iterator<Item = DomRoot<Node>> {
let context_node = context.upcast::<Node>(); let context_node = context.upcast::<Node>();
let context_document = context_node.owner_doc(); let context_document = context_node.owner_doc();
@ -208,6 +215,7 @@ impl ServoParser {
None, None,
None, None,
Default::default(), Default::default(),
can_gc,
); );
// Step 2. // Step 2.
@ -233,7 +241,7 @@ impl ServoParser {
)), )),
ParserKind::Normal, ParserKind::Normal,
); );
parser.parse_complete_string_chunk(String::from(input)); parser.parse_complete_string_chunk(String::from(input), CanGc::note());
// Step 14. // Step 14.
let root_element = document.GetDocumentElement().expect("no document element"); let root_element = document.GetDocumentElement().expect("no document element");
@ -257,7 +265,12 @@ impl ServoParser {
document.set_current_parser(Some(&parser)); 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( let parser = ServoParser::new(
document, document,
Tokenizer::Xml(self::xml::Tokenizer::new(document, url)), 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. // Set as the document's current parser and initialize with `input`, if given.
if let Some(input) = input { if let Some(input) = input {
parser.parse_complete_string_chunk(String::from(input)); parser.parse_complete_string_chunk(String::from(input), can_gc);
} else { } else {
parser.document.set_current_parser(Some(&parser)); parser.document.set_current_parser(Some(&parser));
} }
@ -298,6 +311,7 @@ impl ServoParser {
&self, &self,
script: &HTMLScriptElement, script: &HTMLScriptElement,
result: ScriptResult, result: ScriptResult,
can_gc: CanGc,
) { ) {
assert!(self.suspended.get()); assert!(self.suspended.get());
self.suspended.set(false); self.suspended.set(false);
@ -315,7 +329,7 @@ impl ServoParser {
self.script_nesting_level.set(script_nesting_level); self.script_nesting_level.set(script_nesting_level);
if !self.suspended.get() && !self.aborted.get() { 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()> /// 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()); assert!(self.can_write());
if self.document.has_pending_parsing_blocking_script() { if self.document.has_pending_parsing_blocking_script() {
@ -347,7 +361,7 @@ impl ServoParser {
input.push_back(String::from(chunk).into()); 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() { if self.suspended.get() {
// Parser got suspended, insert remaining input at end of // 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 // 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); assert!(self.script_created_parser);
// Step 4. // Step 4.
@ -375,11 +389,11 @@ impl ServoParser {
} }
// Step 6. // Step 6.
self.parse_sync(); self.parse_sync(can_gc);
} }
// https://html.spec.whatwg.org/multipage/#abort-a-parser // https://html.spec.whatwg.org/multipage/#abort-a-parser
pub fn abort(&self) { pub fn abort(&self, can_gc: CanGc) {
assert!(!self.aborted.get()); assert!(!self.aborted.get());
self.aborted.set(true); self.aborted.set(true);
@ -392,7 +406,7 @@ impl ServoParser {
.set_ready_state(DocumentReadyState::Interactive); .set_ready_state(DocumentReadyState::Interactive);
// Step 3. // Step 3.
self.tokenizer.end(); self.tokenizer.end(can_gc);
self.document.set_current_parser(None); self.document.set_current_parser(None);
// Step 4. // Step 4.
@ -499,7 +513,7 @@ impl ServoParser {
self.push_tendril_input_chunk(chunk); self.push_tendril_input_chunk(chunk);
} }
fn parse_sync(&self) { fn parse_sync(&self, can_gc: CanGc) {
let metadata = TimerMetadata { let metadata = TimerMetadata {
url: self.document.url().as_str().into(), url: self.document.url().as_str().into(),
iframe: TimerMetadataFrameType::RootWindow, iframe: TimerMetadataFrameType::RootWindow,
@ -514,11 +528,11 @@ impl ServoParser {
.upcast::<GlobalScope>() .upcast::<GlobalScope>()
.time_profiler_chan() .time_profiler_chan()
.clone(), .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()); assert!(self.script_input.is_empty());
// This parser will continue to parse while there is either pending input or // 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() { if self.suspended.get() {
return; return;
@ -541,24 +555,24 @@ impl ServoParser {
assert!(self.network_input.is_empty()); assert!(self.network_input.is_empty());
if self.last_chunk_received.get() { 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.document.set_current_parser(Some(self));
self.push_string_input_chunk(input); self.push_string_input_chunk(input);
self.last_chunk_received.set(true); self.last_chunk_received.set(true);
if !self.suspended.get() { 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.document.set_current_parser(Some(self));
self.push_bytes_input_chunk(input); self.push_bytes_input_chunk(input);
if !self.suspended.get() { if !self.suspended.get() {
self.parse_sync(); self.parse_sync(can_gc);
} }
} }
@ -586,7 +600,7 @@ impl ServoParser {
self.document self.document
.window() .window()
.upcast::<GlobalScope>() .upcast::<GlobalScope>()
.perform_a_microtask_checkpoint(); .perform_a_microtask_checkpoint(CanGc::note());
} }
let script_nesting_level = self.script_nesting_level.get(); let script_nesting_level = self.script_nesting_level.get();
@ -606,7 +620,7 @@ impl ServoParser {
} }
// https://html.spec.whatwg.org/multipage/#the-end // https://html.spec.whatwg.org/multipage/#the-end
fn finish(&self) { fn finish(&self, can_gc: CanGc) {
assert!(!self.suspended.get()); assert!(!self.suspended.get());
assert!(self.last_chunk_received.get()); assert!(self.last_chunk_received.get());
assert!(self.script_input.is_empty()); assert!(self.script_input.is_empty());
@ -618,12 +632,13 @@ impl ServoParser {
.set_ready_state(DocumentReadyState::Interactive); .set_ready_state(DocumentReadyState::Interactive);
// Step 2. // Step 2.
self.tokenizer.end(); self.tokenizer.end(can_gc);
self.document.set_current_parser(None); self.document.set_current_parser(None);
// Steps 3-12 are in another castle, namely finish_load. // Steps 3-12 are in another castle, namely finish_load.
let url = self.tokenizer.url().clone(); 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 { impl Tokenizer {
fn feed(&self, input: &BufferQueue) -> TokenizerResult<DomRoot<HTMLScriptElement>> { fn feed(
&self,
input: &BufferQueue,
can_gc: CanGc,
) -> TokenizerResult<DomRoot<HTMLScriptElement>> {
match *self { match *self {
Tokenizer::Html(ref tokenizer) => tokenizer.feed(input), 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), Tokenizer::Xml(ref tokenizer) => tokenizer.feed(input),
} }
} }
fn end(&self) { fn end(&self, can_gc: CanGc) {
match *self { match *self {
Tokenizer::Html(ref tokenizer) => tokenizer.end(), 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(), Tokenizer::Xml(ref tokenizer) => tokenizer.end(),
} }
} }
@ -797,7 +816,7 @@ impl FetchResponseListener for ParserContext {
Some(csp_list) 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, Some(parser) => parser,
None => return, None => return,
}; };
@ -829,7 +848,7 @@ impl FetchResponseListener for ParserContext {
self.is_synthesized_document = true; self.is_synthesized_document = true;
let page = "<html><body></body></html>".into(); let page = "<html><body></body></html>".into();
parser.push_string_input_chunk(page); parser.push_string_input_chunk(page);
parser.parse_sync(); parser.parse_sync(CanGc::note());
let doc = &parser.document; let doc = &parser.document;
let doc_body = DomRoot::upcast::<Node>(doc.GetBody().unwrap()); 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 // https://html.spec.whatwg.org/multipage/#read-text
let page = "<pre>\n".into(); let page = "<pre>\n".into();
parser.push_string_input_chunk(page); parser.push_string_input_chunk(page);
parser.parse_sync(); parser.parse_sync(CanGc::note());
parser.tokenizer.set_plaintext_state(); parser.tokenizer.set_plaintext_state();
}, },
(mime::TEXT, mime::HTML, _) => match error { (mime::TEXT, mime::HTML, _) => match error {
@ -856,21 +875,21 @@ impl FetchResponseListener for ParserContext {
let page = let page =
page.replace("${secret}", &net_traits::PRIVILEGED_SECRET.to_string()); page.replace("${secret}", &net_traits::PRIVILEGED_SECRET.to_string());
parser.push_string_input_chunk(page); parser.push_string_input_chunk(page);
parser.parse_sync(); parser.parse_sync(CanGc::note());
}, },
Some(NetworkError::Internal(reason)) => { Some(NetworkError::Internal(reason)) => {
self.is_synthesized_document = true; self.is_synthesized_document = true;
let page = resources::read_string(Resource::NetErrorHTML); let page = resources::read_string(Resource::NetErrorHTML);
let page = page.replace("${reason}", &reason); let page = page.replace("${reason}", &reason);
parser.push_string_input_chunk(page); parser.push_string_input_chunk(page);
parser.parse_sync(); parser.parse_sync(CanGc::note());
}, },
Some(NetworkError::Crash(details)) => { Some(NetworkError::Crash(details)) => {
self.is_synthesized_document = true; self.is_synthesized_document = true;
let page = resources::read_string(Resource::CrashHTML); let page = resources::read_string(Resource::CrashHTML);
let page = page.replace("${details}", &details); let page = page.replace("${details}", &details);
parser.push_string_input_chunk(page); parser.push_string_input_chunk(page);
parser.parse_sync(); parser.parse_sync(CanGc::note());
}, },
Some(_) => {}, Some(_) => {},
None => {}, None => {},
@ -888,7 +907,7 @@ impl FetchResponseListener for ParserContext {
); );
self.is_synthesized_document = true; self.is_synthesized_document = true;
parser.push_string_input_chunk(page); parser.push_string_input_chunk(page);
parser.parse_sync(); parser.parse_sync(CanGc::note());
}, },
} }
} }
@ -905,7 +924,7 @@ impl FetchResponseListener for ParserContext {
return; return;
} }
let _realm = enter_realm(&*parser); 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 // 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); parser.last_chunk_received.set(true);
if !parser.suspended.get() { if !parser.suspended.get() {
parser.parse_sync(); parser.parse_sync(CanGc::note());
} }
// TODO: Only update if this is the current document resource. // TODO: Only update if this is the current document resource.
@ -1000,6 +1019,7 @@ fn insert(
reference_child: Option<&Node>, reference_child: Option<&Node>,
child: NodeOrText<Dom<Node>>, child: NodeOrText<Dom<Node>>,
parsing_algorithm: ParsingAlgorithm, parsing_algorithm: ParsingAlgorithm,
can_gc: CanGc,
) { ) {
match child { match child {
NodeOrText::AppendNode(n) => { NodeOrText::AppendNode(n) => {
@ -1013,7 +1033,7 @@ fn insert(
} }
parent.InsertBefore(&n, reference_child).unwrap(); parent.InsertBefore(&n, reference_child).unwrap();
if element_in_non_fragment { if element_in_non_fragment {
ScriptThread::pop_current_element_queue(); ScriptThread::pop_current_element_queue(can_gc);
} }
}, },
NodeOrText::AppendText(t) => { NodeOrText::AppendText(t) => {
@ -1076,7 +1096,7 @@ impl TreeSink for Sink {
let template = target let template = target
.downcast::<HTMLTemplateElement>() .downcast::<HTMLTemplateElement>()
.expect("tried to get template contents of non-HTMLTemplateElement in HTML parsing"); .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 { fn same_node(&self, x: &Dom<Node>, y: &Dom<Node>) -> bool {
@ -1110,6 +1130,7 @@ impl TreeSink for Sink {
&self.document, &self.document,
ElementCreator::ParserCreated(self.current_line.get()), ElementCreator::ParserCreated(self.current_line.get()),
self.parsing_algorithm, self.parsing_algorithm,
CanGc::note(),
); );
Dom::from_ref(element.upcast()) Dom::from_ref(element.upcast())
} }
@ -1167,7 +1188,13 @@ impl TreeSink for Sink {
.GetParentNode() .GetParentNode()
.expect("append_before_sibling called on node without parent"); .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>) { fn parse_error(&self, msg: Cow<'static, str>) {
@ -1185,7 +1212,7 @@ impl TreeSink for Sink {
#[allow(crown::unrooted_must_root)] #[allow(crown::unrooted_must_root)]
fn append(&self, parent: &Dom<Node>, child: NodeOrText<Dom<Node>>) { 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)] #[allow(crown::unrooted_must_root)]
@ -1289,6 +1316,7 @@ fn create_element_for_token(
document: &Document, document: &Document,
creator: ElementCreator, creator: ElementCreator,
parsing_algorithm: ParsingAlgorithm, parsing_algorithm: ParsingAlgorithm,
can_gc: CanGc,
) -> DomRoot<Element> { ) -> DomRoot<Element> {
// Step 3. // Step 3.
let is = attrs let is = attrs
@ -1312,7 +1340,7 @@ fn create_element_for_token(
document document
.window() .window()
.upcast::<GlobalScope>() .upcast::<GlobalScope>()
.perform_a_microtask_checkpoint(); .perform_a_microtask_checkpoint(can_gc);
} }
// Step 6.3 // Step 6.3
ScriptThread::push_new_element_queue() ScriptThread::push_new_element_queue()
@ -1325,7 +1353,15 @@ fn create_element_for_token(
CustomElementCreationMode::Asynchronous 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 // https://html.spec.whatwg.org/multipage#the-input-element:value-sanitization-algorithm-3
// says to invoke sanitization "when an input element is first created"; // says to invoke sanitization "when an input element is first created";
@ -1353,7 +1389,7 @@ fn create_element_for_token(
// Step 9. // Step 9.
if will_execute_script { if will_execute_script {
// Steps 9.1 - 9.2. // Steps 9.1 - 9.2.
ScriptThread::pop_current_element_queue(); ScriptThread::pop_current_element_queue(CanGc::note());
// Step 9.3. // Step 9.3.
document.decrement_throw_on_dynamic_markup_insertion_counter(); document.decrement_throw_on_dynamic_markup_insertion_counter();
} }

View file

@ -144,7 +144,7 @@ use crate::layout_image::fetch_image_for_layout;
use crate::microtask::MicrotaskQueue; use crate::microtask::MicrotaskQueue;
use crate::realms::InRealm; use crate::realms::InRealm;
use crate::script_runtime::{ use crate::script_runtime::{
CommonScriptMsg, JSContext, Runtime, ScriptChan, ScriptPort, ScriptThreadEventCategory, CanGc, CommonScriptMsg, JSContext, Runtime, ScriptChan, ScriptPort, ScriptThreadEventCategory,
}; };
use crate::script_thread::{ use crate::script_thread::{
ImageCacheMsg, MainThreadScriptChan, MainThreadScriptMsg, ScriptThread, ImageCacheMsg, MainThreadScriptChan, MainThreadScriptMsg, ScriptThread,
@ -676,10 +676,10 @@ impl WindowMethods for Window {
} }
// https://html.spec.whatwg.org/multipage/#dom-window-stop // https://html.spec.whatwg.org/multipage/#dom-window-stop
fn Stop(&self) { fn Stop(&self, can_gc: CanGc) {
// TODO: Cancel ongoing navigation. // TODO: Cancel ongoing navigation.
let doc = self.Document(); let doc = self.Document();
doc.abort(); doc.abort(can_gc);
} }
// https://html.spec.whatwg.org/multipage/#dom-open // https://html.spec.whatwg.org/multipage/#dom-open

View file

@ -159,6 +159,7 @@ impl Worker {
global.wgpu_id_hub(), global.wgpu_id_hub(),
control_receiver, control_receiver,
context_sender, context_sender,
CanGc::note(),
); );
let context = context_receiver let context = context_receiver

View file

@ -950,7 +950,7 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
#[allow(unsafe_code)] #[allow(unsafe_code)]
/// <https://xhr.spec.whatwg.org/#the-response-attribute> /// <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()); rooted!(in(*cx) let mut rval = UndefinedValue());
match self.response_type.get() { match self.response_type.get() {
XMLHttpRequestResponseType::_empty | XMLHttpRequestResponseType::Text => unsafe { XMLHttpRequestResponseType::_empty | XMLHttpRequestResponseType::Text => unsafe {
@ -971,7 +971,8 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
}, },
// Step 2 // Step 2
XMLHttpRequestResponseType::Document => unsafe { 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 { XMLHttpRequestResponseType::Json => unsafe {
self.json_response(cx).to_jsval(*cx, rval.handle_mut()); 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> /// <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() { match self.response_type.get() {
XMLHttpRequestResponseType::_empty | XMLHttpRequestResponseType::Document => { XMLHttpRequestResponseType::_empty | XMLHttpRequestResponseType::Document => {
// Step 3 // Step 3
if let XMLHttpRequestState::Done = self.ready_state.get() { if let XMLHttpRequestState::Done = self.ready_state.get() {
Ok(self.document_response()) Ok(self.document_response(can_gc))
} else { } else {
// Step 2 // Step 2
Ok(None) Ok(None)
@ -1367,7 +1368,7 @@ impl XMLHttpRequest {
} }
/// <https://xhr.spec.whatwg.org/#document-response> /// <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 // Caching: if we have existing response xml, redirect it directly
let response = self.response_xml.get(); let response = self.response_xml.get();
if response.is_some() { if response.is_some() {
@ -1392,12 +1393,12 @@ impl XMLHttpRequest {
} else { } else {
// TODO Step 5.2 "If charset is null, prescan the first 1024 bytes of xhrs received bytes" // TODO Step 5.2 "If charset is null, prescan the first 1024 bytes of xhrs received bytes"
// Step 5 // Step 5
temp_doc = self.document_text_html(); temp_doc = self.document_text_html(can_gc);
} }
}, },
// Step 7 // Step 7
None => { 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 // Not sure it the parser should throw an error for this case
// The specification does not indicates this test, // The specification does not indicates this test,
// but for now we check the document has no child nodes // 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.type_() == mime::APPLICATION && mime.subtype() == mime::XML) ||
mime.suffix() == Some(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 // Not sure it the parser should throw an error for this case
// The specification does not indicates this test, // The specification does not indicates this test,
// but for now we check the document has no child nodes // but for now we check the document has no child nodes
@ -1488,29 +1489,39 @@ impl XMLHttpRequest {
self.response_json.get() 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 charset = self.final_charset().unwrap_or(UTF_8);
let wr = self.global(); let wr = self.global();
let response = self.response.borrow(); let response = self.response.borrow();
let (decoded, _, _) = charset.decode(&response); 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 // 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 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 charset = self.final_charset().unwrap_or(UTF_8);
let wr = self.global(); let wr = self.global();
let response = self.response.borrow(); let response = self.response.borrow();
let (decoded, _, _) = charset.decode(&response); 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 // 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 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 wr = self.global();
let win = wr.as_window(); let win = wr.as_window();
let doc = win.Document(); let doc = win.Document();
@ -1536,6 +1547,7 @@ impl XMLHttpRequest {
None, None,
None, None,
Default::default(), Default::default(),
can_gc,
) )
} }

View file

@ -23,7 +23,7 @@ use crate::dom::htmlimageelement::ImageElementMicrotask;
use crate::dom::htmlmediaelement::MediaElementMicrotask; use crate::dom::htmlmediaelement::MediaElementMicrotask;
use crate::dom::mutationobserver::MutationObserver; use crate::dom::mutationobserver::MutationObserver;
use crate::realms::enter_realm; 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; use crate::script_thread::ScriptThread;
/// A collection of microtasks in FIFO order. /// A collection of microtasks in FIFO order.
@ -46,7 +46,7 @@ pub enum Microtask {
} }
pub trait MicrotaskRunnable { pub trait MicrotaskRunnable {
fn handler(&self) {} fn handler(&self, _can_gc: CanGc) {}
fn enter_realm(&self) -> JSAutoRealm; fn enter_realm(&self) -> JSAutoRealm;
} }
@ -87,6 +87,7 @@ impl MicrotaskQueue {
cx: JSContext, cx: JSContext,
target_provider: F, target_provider: F,
globalscopes: Vec<DomRoot<GlobalScope>>, globalscopes: Vec<DomRoot<GlobalScope>>,
_can_gc: CanGc,
) where ) where
F: Fn(PipelineId) -> Option<DomRoot<GlobalScope>>, F: Fn(PipelineId) -> Option<DomRoot<GlobalScope>>,
{ {
@ -127,14 +128,14 @@ impl MicrotaskQueue {
}, },
Microtask::MediaElement(ref task) => { Microtask::MediaElement(ref task) => {
let _realm = task.enter_realm(); let _realm = task.enter_realm();
task.handler(); task.handler(CanGc::note());
}, },
Microtask::ImageElement(ref task) => { Microtask::ImageElement(ref task) => {
let _realm = task.enter_realm(); let _realm = task.enter_realm();
task.handler(); task.handler(CanGc::note());
}, },
Microtask::CustomElementReaction => { Microtask::CustomElementReaction => {
ScriptThread::invoke_backup_element_queue(); ScriptThread::invoke_backup_element_queue(CanGc::note());
}, },
Microtask::NotifyMutationObservers => { Microtask::NotifyMutationObservers => {
MutationObserver::notify_mutation_observers(); MutationObserver::notify_mutation_observers();

View file

@ -72,7 +72,7 @@ use crate::dom::window::Window;
use crate::dom::worker::TrustedWorkerAddress; use crate::dom::worker::TrustedWorkerAddress;
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; 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::TaskBox;
use crate::task_source::TaskSourceName; use crate::task_source::TaskSourceName;
@ -1091,7 +1091,7 @@ impl FetchResponseListener for ModuleContext {
if let Some(window) = global.downcast::<Window>() { if let Some(window) = global.downcast::<Window>() {
window window
.Document() .Document()
.finish_load(LoadType::Script(self.url.clone())); .finish_load(LoadType::Script(self.url.clone()), CanGc::note());
} }
// Step 9-1 & 9-2. // Step 9-1 & 9-2.

View file

@ -145,8 +145,8 @@ use crate::microtask::{Microtask, MicrotaskQueue};
use crate::realms::enter_realm; use crate::realms::enter_realm;
use crate::script_module::ScriptFetchOptions; use crate::script_module::ScriptFetchOptions;
use crate::script_runtime::{ use crate::script_runtime::{
get_reports, new_rt_and_cx, CommonScriptMsg, ContextForRequestInterrupt, JSContext, Runtime, get_reports, new_rt_and_cx, CanGc, CommonScriptMsg, ContextForRequestInterrupt, JSContext,
ScriptChan, ScriptPort, ScriptThreadEventCategory, Runtime, ScriptChan, ScriptPort, ScriptThreadEventCategory,
}; };
use crate::task_manager::TaskManager; use crate::task_manager::TaskManager;
use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue}; use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
@ -840,7 +840,7 @@ impl ScriptThreadFactory for ScriptThread {
let reporter_name = format!("script-reporter-{:?}", id); let reporter_name = format!("script-reporter-{:?}", id);
mem_profiler_chan.run_with_memory_reporting( mem_profiler_chan.run_with_memory_reporting(
|| { || {
script_thread.start(); script_thread.start(CanGc::note());
let _ = script_thread.content_process_shutdown_chan.send(()); let _ = script_thread.content_process_shutdown_chan.send(());
}, },
reporter_name, reporter_name,
@ -935,10 +935,11 @@ impl ScriptThread {
pub fn page_headers_available( pub fn page_headers_available(
id: &PipelineId, id: &PipelineId,
metadata: Option<Metadata>, metadata: Option<Metadata>,
can_gc: CanGc,
) -> Option<DomRoot<ServoParser>> { ) -> Option<DomRoot<ServoParser>> {
SCRIPT_THREAD_ROOT.with(|root| { SCRIPT_THREAD_ROOT.with(|root| {
let script_thread = unsafe { &*root.get().unwrap() }; 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| { SCRIPT_THREAD_ROOT.with(|root| {
if let Some(script_thread) = root.get() { if let Some(script_thread) = root.get() {
let script_thread = unsafe { &*script_thread }; let script_thread = unsafe { &*script_thread };
script_thread script_thread
.custom_element_reaction_stack .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| { SCRIPT_THREAD_ROOT.with(|root| {
if let Some(script_thread) = root.get() { if let Some(script_thread) = root.get() {
let script_thread = unsafe { &*script_thread }; let script_thread = unsafe { &*script_thread };
script_thread script_thread
.custom_element_reaction_stack .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 /// Starts the script thread. After calling this method, the script thread will loop receiving
/// messages on its port. /// messages on its port.
pub fn start(&self) { pub fn start(&self, _can_gc: CanGc) {
debug!("Starting script thread."); debug!("Starting script thread.");
while self.handle_msgs() { while self.handle_msgs(CanGc::note()) {
// Go on... // Go on...
debug!("Running script thread."); debug!("Running script thread.");
} }
@ -1781,7 +1782,7 @@ impl ScriptThread {
} }
/// Handle incoming messages from other tasks and the task queue. /// 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::{ use self::MixedMessage::{
FromConstellation, FromDevtools, FromImageCache, FromScript, FromWebGPUServer, FromConstellation, FromDevtools, FromImageCache, FromScript, FromWebGPUServer,
}; };
@ -1893,7 +1894,7 @@ impl ScriptThread {
// Run the "update the rendering" task. // Run the "update the rendering" task.
task.run_box(); task.run_box();
// Always perform a microtrask checkpoint after running a task. // Always perform a microtrask checkpoint after running a task.
self.perform_a_microtask_checkpoint(); self.perform_a_microtask_checkpoint(CanGc::note());
}, },
FromScript(MainThreadScriptMsg::Inactive) => { FromScript(MainThreadScriptMsg::Inactive) => {
// An event came-in from a document that is not fully-active, it has been stored by the task-queue. // 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. // If we've received the closed signal from the BHM, only handle exit messages.
match msg { match msg {
FromConstellation(ConstellationControlMsg::ExitScriptThread) => { FromConstellation(ConstellationControlMsg::ExitScriptThread) => {
self.handle_exit_script_thread_msg(); self.handle_exit_script_thread_msg(CanGc::note());
return false; return false;
}, },
FromConstellation(ConstellationControlMsg::ExitPipeline( FromConstellation(ConstellationControlMsg::ExitPipeline(
pipeline_id, pipeline_id,
discard_browsing_context, 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 || { let result = self.profile_event(category, pipeline_id, move || {
match msg { match msg {
FromConstellation(ConstellationControlMsg::ExitScriptThread) => { FromConstellation(ConstellationControlMsg::ExitScriptThread) => {
self.handle_exit_script_thread_msg(); self.handle_exit_script_thread_msg(CanGc::note());
return Some(false); 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), FromScript(inner_msg) => self.handle_msg_from_script(inner_msg),
FromDevtools(inner_msg) => self.handle_msg_from_devtools(inner_msg), FromDevtools(inner_msg) => self.handle_msg_from_devtools(inner_msg),
FromImageCache(inner_msg) => self.handle_msg_from_image_cache(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 // 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. // 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 value
} }
fn handle_msg_from_constellation(&self, msg: ConstellationControlMsg) { fn handle_msg_from_constellation(&self, msg: ConstellationControlMsg, can_gc: CanGc) {
match msg { match msg {
ConstellationControlMsg::StopDelayingLoadEventsMode(pipeline_id) => { ConstellationControlMsg::StopDelayingLoadEventsMode(pipeline_id) => {
self.handle_stop_delaying_load_events_mode(pipeline_id) self.handle_stop_delaying_load_events_mode(pipeline_id)
@ -2273,6 +2280,7 @@ impl ScriptThread {
browsing_context_id, browsing_context_id,
load_data, load_data,
replace, replace,
can_gc,
), ),
ConstellationControlMsg::UnloadDocument(pipeline_id) => { ConstellationControlMsg::UnloadDocument(pipeline_id) => {
self.handle_unload_document(pipeline_id) self.handle_unload_document(pipeline_id)
@ -2325,6 +2333,7 @@ impl ScriptThread {
top_level_browsing_context_id, top_level_browsing_context_id,
new_pipeline_id, new_pipeline_id,
reason, reason,
can_gc,
), ),
ConstellationControlMsg::UpdateHistoryState(pipeline_id, history_state_id, url) => { ConstellationControlMsg::UpdateHistoryState(pipeline_id, history_state_id, url) => {
self.handle_update_history_state_msg(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, target: browsing_context_id,
parent: parent_id, parent: parent_id,
child: child_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( ConstellationControlMsg::DispatchStorageEvent(
pipeline_id, pipeline_id,
storage, storage,
@ -2359,13 +2368,13 @@ impl ScriptThread {
}, },
ConstellationControlMsg::Reload(pipeline_id) => self.handle_reload(pipeline_id), ConstellationControlMsg::Reload(pipeline_id) => self.handle_reload(pipeline_id),
ConstellationControlMsg::ExitPipeline(pipeline_id, discard_browsing_context) => { 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) => { ConstellationControlMsg::PaintMetric(pipeline_id, metric_type, metric_value) => {
self.handle_paint_metric(pipeline_id, metric_type, metric_value) self.handle_paint_metric(pipeline_id, metric_type, metric_value)
}, },
ConstellationControlMsg::MediaSessionAction(pipeline_id, action) => { 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) => { ConstellationControlMsg::SetWebGPUPort(port) => {
if self.webgpu_port.borrow().is_some() { if self.webgpu_port.borrow().is_some() {
@ -3050,13 +3059,14 @@ impl ScriptThread {
top_level_browsing_context_id: TopLevelBrowsingContextId, top_level_browsing_context_id: TopLevelBrowsingContextId,
new_pipeline_id: PipelineId, new_pipeline_id: PipelineId,
reason: UpdatePipelineIdReason, reason: UpdatePipelineIdReason,
can_gc: CanGc,
) { ) {
let frame_element = self let frame_element = self
.documents .documents
.borrow() .borrow()
.find_iframe(parent_pipeline_id, browsing_context_id); .find_iframe(parent_pipeline_id, browsing_context_id);
if let Some(frame_element) = frame_element { 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) { if let Some(window) = self.documents.borrow().find_window(new_pipeline_id) {
@ -3123,6 +3133,7 @@ impl ScriptThread {
&self, &self,
id: &PipelineId, id: &PipelineId,
metadata: Option<Metadata>, metadata: Option<Metadata>,
_can_gc: CanGc,
) -> Option<DomRoot<ServoParser>> { ) -> Option<DomRoot<ServoParser>> {
let idx = self let idx = self
.incomplete_loads .incomplete_loads
@ -3161,7 +3172,7 @@ impl ScriptThread {
}; };
let load = self.incomplete_loads.borrow_mut().remove(idx); 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 => { None => {
assert!(self.closed_pipelines.borrow().contains(id)); assert!(self.closed_pipelines.borrow().contains(id));
@ -3244,7 +3255,12 @@ impl ScriptThread {
} }
/// Handles a request to exit a pipeline and shut down layout. /// 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."); debug!("{id}: Starting pipeline exit.");
self.closed_pipelines.borrow_mut().insert(id); self.closed_pipelines.borrow_mut().insert(id);
@ -3261,7 +3277,7 @@ impl ScriptThread {
.any(|load| load.pipeline_id == id)); .any(|load| load.pipeline_id == id));
if let Some(parser) = document.get_current_parser() { if let Some(parser) = document.get_current_parser() {
parser.abort(); parser.abort(can_gc);
} }
debug!("{id}: Shutting down layout"); debug!("{id}: Shutting down layout");
@ -3298,7 +3314,7 @@ impl ScriptThread {
} }
/// Handles a request to exit the script thread and shut down layout. /// 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."); debug!("Exiting script thread.");
let mut pipeline_ids = Vec::new(); let mut pipeline_ids = Vec::new();
@ -3318,7 +3334,7 @@ impl ScriptThread {
); );
for pipeline_id in pipeline_ids { 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(); self.background_hang_monitor.unregister();
@ -3399,13 +3415,14 @@ impl ScriptThread {
parent_id: PipelineId, parent_id: PipelineId,
browsing_context_id: BrowsingContextId, browsing_context_id: BrowsingContextId,
child_id: PipelineId, child_id: PipelineId,
can_gc: CanGc,
) { ) {
let iframe = self let iframe = self
.documents .documents
.borrow() .borrow()
.find_iframe(parent_id, browsing_context_id); .find_iframe(parent_id, browsing_context_id);
match iframe { 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), 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 /// The entry point to document loading. Defines bindings, sets up the window and document
/// objects, parses HTML and CSS, and kicks off initial layout. /// 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(); let final_url = metadata.final_url.clone();
{ {
self.script_sender self.script_sender
@ -3736,6 +3758,7 @@ impl ScriptThread {
referrer_policy, referrer_policy,
Some(status_code), Some(status_code),
incomplete.canceller, incomplete.canceller,
CanGc::note(),
); );
document.set_ready_state(DocumentReadyState::Loading); document.set_ready_state(DocumentReadyState::Loading);
@ -3758,6 +3781,7 @@ impl ScriptThread {
window_proxy.top_level_browsing_context_id(), window_proxy.top_level_browsing_context_id(),
incomplete.pipeline_id, incomplete.pipeline_id,
UpdatePipelineIdReason::Navigation, UpdatePipelineIdReason::Navigation,
can_gc,
); );
} }
@ -3776,9 +3800,9 @@ impl ScriptThread {
document.set_navigation_start(incomplete.navigation_start); document.set_navigation_start(incomplete.navigation_start);
if is_html_document == IsHTMLDocument::NonHTMLDocument { 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 { } else {
ServoParser::parse_html_document(&document, None, final_url); ServoParser::parse_html_document(&document, None, final_url, CanGc::note());
} }
if incomplete.activity == DocumentActivity::FullyActive { if incomplete.activity == DocumentActivity::FullyActive {
@ -3901,13 +3925,14 @@ impl ScriptThread {
browsing_context_id: BrowsingContextId, browsing_context_id: BrowsingContextId,
load_data: LoadData, load_data: LoadData,
replace: HistoryEntryReplacement, replace: HistoryEntryReplacement,
can_gc: CanGc,
) { ) {
let iframe = self let iframe = self
.documents .documents
.borrow() .borrow()
.find_iframe(parent_pipeline_id, browsing_context_id); .find_iframe(parent_pipeline_id, browsing_context_id);
if let Some(iframe) = iframe { 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) { if let Some(window) = self.documents.borrow().find_window(pipeline_id) {
let media_session = window.Navigator().MediaSession(); let media_session = window.Navigator().MediaSession();
media_session.handle_action(action); media_session.handle_action(action, can_gc);
} else { } else {
warn!("No MediaSession for this pipeline ID"); 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. // Only perform the checkpoint if we're not shutting down.
if self.can_continue_running_inner() { if self.can_continue_running_inner() {
let globals = self let globals = self
@ -4211,6 +4241,7 @@ impl ScriptThread {
self.get_cx(), self.get_cx(),
|id| self.documents.borrow().find_global(id), |id| self.documents.borrow().find_global(id),
globals, globals,
can_gc,
) )
} }
} }

View file

@ -29,7 +29,7 @@ use crate::dom::serviceworkerglobalscope::{
ServiceWorkerControlMsg, ServiceWorkerGlobalScope, ServiceWorkerScriptMsg, ServiceWorkerControlMsg, ServiceWorkerGlobalScope, ServiceWorkerScriptMsg,
}; };
use crate::dom::serviceworkerregistration::longest_prefix_match; use crate::dom::serviceworkerregistration::longest_prefix_match;
use crate::script_runtime::ContextForRequestInterrupt; use crate::script_runtime::{CanGc, ContextForRequestInterrupt};
enum Message { enum Message {
FromResource(CustomResponseMediator), FromResource(CustomResponseMediator),
@ -250,10 +250,12 @@ impl ServiceWorkerManager {
None None
} }
fn handle_message(&mut self) { fn handle_message(&mut self, _can_gc: CanGc) {
while let Ok(message) = self.receive_message() { while let Ok(message) = self.receive_message() {
let should_continue = match 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), Message::FromResource(msg) => self.handle_message_from_resource(msg),
}; };
if !should_continue { 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 { match msg {
ServiceWorkerMsg::Timeout(_scope) => { ServiceWorkerMsg::Timeout(_scope) => {
// TODO: https://w3c.github.io/ServiceWorker/#terminate-service-worker // TODO: https://w3c.github.io/ServiceWorker/#terminate-service-worker
@ -305,7 +307,7 @@ impl ServiceWorkerManager {
self.handle_register_job(job); self.handle_register_job(job);
}, },
JobType::Update => { JobType::Update => {
self.handle_update_job(job); self.handle_update_job(job, can_gc);
}, },
JobType::Unregister => { JobType::Unregister => {
// TODO: https://w3c.github.io/ServiceWorker/#unregister-algorithm // TODO: https://w3c.github.io/ServiceWorker/#unregister-algorithm
@ -380,7 +382,7 @@ impl ServiceWorkerManager {
} }
/// <https://w3c.github.io/ServiceWorker/#update> /// <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 // Step 1: Get registation
if let Some(registration) = self.registrations.get_mut(&job.scope_url) { if let Some(registration) = self.registrations.get_mut(&job.scope_url) {
// Step 3. // Step 3.
@ -403,8 +405,12 @@ impl ServiceWorkerManager {
// Very roughly steps 5 to 18. // Very roughly steps 5 to 18.
// TODO: implement all steps precisely. // TODO: implement all steps precisely.
let (new_worker, join_handle, control_sender, context, closing) = let (new_worker, join_handle, control_sender, context, closing) = update_serviceworker(
update_serviceworker(self.own_sender.clone(), job.scope_url.clone(), scope_things); 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. // 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); registration.note_worker_thread(join_handle, control_sender, context, closing);
@ -443,6 +449,7 @@ fn update_serviceworker(
own_sender: IpcSender<ServiceWorkerMsg>, own_sender: IpcSender<ServiceWorkerMsg>,
scope_url: ServoUrl, scope_url: ServoUrl,
scope_things: ScopeThings, scope_things: ScopeThings,
can_gc: CanGc,
) -> ( ) -> (
ServiceWorker, ServiceWorker,
JoinHandle<()>, JoinHandle<()>,
@ -468,6 +475,7 @@ fn update_serviceworker(
control_receiver, control_receiver,
context_sender, context_sender,
closing.clone(), closing.clone(),
can_gc,
); );
let context = context_receiver let context = context_receiver
@ -504,7 +512,7 @@ impl ServiceWorkerManagerFactory for ServiceWorkerManager {
resource_port, resource_port,
constellation_sender, constellation_sender,
) )
.handle_message() .handle_message(CanGc::note())
}; };
if thread::Builder::new() if thread::Builder::new()
.name("SvcWorkerManager".to_owned()) .name("SvcWorkerManager".to_owned())

View file

@ -44,6 +44,7 @@ use crate::dom::performanceresourcetiming::InitiatorType;
use crate::dom::shadowroot::ShadowRoot; use crate::dom::shadowroot::ShadowRoot;
use crate::fetch::create_a_potential_cors_request; use crate::fetch::create_a_potential_cors_request;
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
use crate::script_runtime::CanGc;
pub trait StylesheetOwner { pub trait StylesheetOwner {
/// Returns whether this element was inserted by the parser (i.e., it should /// 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.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) { if let Some(any_failed) = owner.load_finished(successful) {
let event = if any_failed { let event = if any_failed {