script: Move TaskManager to GlobalScope (#34827)

This is a simplification of the internal `TaskQueue` API that moves the
`TaskManager` to the `GlobalScope` itself. In addition, the handling of
cancellers is moved to the `TaskManager` as well. This means that no
arguments other than the `task` are necessary for queueing tasks, which
makes the API a lot easier to use and cleaner.

`TaskSource` now also keeps a copy of the canceller with it, so that
they always know the proper way to cancel any tasks queued on them.

There is one complication here. The event loop `sender` for dedicated
workers is constantly changing as it is set to `None` when not handling
messages. This is because this sender keeps a handle to the main
thread's `Worker` object, preventing garbage collection while any
messages are still in flight or being handled. This change allows
setting the `sender` on the `TaskManager` to `None` to allow proper
garbabge collection.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2025-01-04 09:41:50 +01:00 committed by GitHub
parent 75a22cfe2e
commit b2eda71952
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
54 changed files with 1060 additions and 1516 deletions

View file

@ -40,8 +40,7 @@ use crate::dom::readablestream::{get_read_promise_bytes, get_read_promise_done,
use crate::dom::urlsearchparams::URLSearchParams; use crate::dom::urlsearchparams::URLSearchParams;
use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; use crate::realms::{enter_realm, AlreadyInRealm, InRealm};
use crate::script_runtime::{CanGc, JSContext}; use crate::script_runtime::{CanGc, JSContext};
use crate::task::TaskCanceller; use crate::task_source::TaskSource;
use crate::task_source::{TaskSource, TaskSourceName};
/// The Dom object, or ReadableStream, that is the source of a body. /// The Dom object, or ReadableStream, that is the source of a body.
/// <https://fetch.spec.whatwg.org/#concept-body-source> /// <https://fetch.spec.whatwg.org/#concept-body-source>
@ -72,7 +71,6 @@ enum StopReading {
struct TransmitBodyConnectHandler { struct TransmitBodyConnectHandler {
stream: Trusted<ReadableStream>, stream: Trusted<ReadableStream>,
task_source: TaskSource, task_source: TaskSource,
canceller: TaskCanceller,
bytes_sender: Option<IpcSender<BodyChunkResponse>>, bytes_sender: Option<IpcSender<BodyChunkResponse>>,
control_sender: IpcSender<BodyChunkRequest>, control_sender: IpcSender<BodyChunkRequest>,
in_memory: Option<Vec<u8>>, in_memory: Option<Vec<u8>>,
@ -84,7 +82,6 @@ impl TransmitBodyConnectHandler {
pub fn new( pub fn new(
stream: Trusted<ReadableStream>, stream: Trusted<ReadableStream>,
task_source: TaskSource, task_source: TaskSource,
canceller: TaskCanceller,
control_sender: IpcSender<BodyChunkRequest>, control_sender: IpcSender<BodyChunkRequest>,
in_memory: Option<Vec<u8>>, in_memory: Option<Vec<u8>>,
source: BodySource, source: BodySource,
@ -92,7 +89,6 @@ impl TransmitBodyConnectHandler {
TransmitBodyConnectHandler { TransmitBodyConnectHandler {
stream, stream,
task_source, task_source,
canceller,
bytes_sender: None, bytes_sender: None,
control_sender, control_sender,
in_memory, in_memory,
@ -178,8 +174,9 @@ impl TransmitBodyConnectHandler {
// If we're using an actual ReadableStream, acquire a reader for it. // If we're using an actual ReadableStream, acquire a reader for it.
if self.source == BodySource::Null { if self.source == BodySource::Null {
let stream = self.stream.clone(); let stream = self.stream.clone();
let _ = self.task_source.queue_with_canceller( let _ = self
task!(start_reading_request_body_stream: move || { .task_source
.queue(task!(start_reading_request_body_stream: move || {
// Step 1, Let body be requests body. // Step 1, Let body be requests body.
let rooted_stream = stream.root(); let rooted_stream = stream.root();
@ -190,9 +187,7 @@ impl TransmitBodyConnectHandler {
.expect("Couldn't acquire a reader for the body stream."); .expect("Couldn't acquire a reader for the body stream.");
// Note: this algorithm continues when the first chunk is requested by `net`. // Note: this algorithm continues when the first chunk is requested by `net`.
}), }));
&self.canceller,
);
} }
} }
@ -236,7 +231,7 @@ impl TransmitBodyConnectHandler {
return; return;
} }
let _ = self.task_source.queue_with_canceller( let _ = self.task_source.queue(
task!(setup_native_body_promise_handler: move || { task!(setup_native_body_promise_handler: move || {
let rooted_stream = stream.root(); let rooted_stream = stream.root();
let global = rooted_stream.global(); let global = rooted_stream.global();
@ -265,8 +260,7 @@ impl TransmitBodyConnectHandler {
let realm = enter_realm(&*global); let realm = enter_realm(&*global);
let comp = InRealm::Entered(&realm); let comp = InRealm::Entered(&realm);
promise.append_native_handler(&handler, comp, CanGc::note()); promise.append_native_handler(&handler, comp, CanGc::note());
}), })
&self.canceller,
); );
} }
} }
@ -379,7 +373,6 @@ impl ExtractedBody {
let global = stream.global(); let global = stream.global();
let task_source = global.task_manager().networking_task_source(); let task_source = global.task_manager().networking_task_source();
let canceller = global.task_canceller(TaskSourceName::Networking);
// In case of the data being in-memory, send everything in one chunk, by-passing SM. // In case of the data being in-memory, send everything in one chunk, by-passing SM.
let in_memory = stream.get_in_memory_bytes(); let in_memory = stream.get_in_memory_bytes();
@ -392,7 +385,6 @@ impl ExtractedBody {
let mut body_handler = TransmitBodyConnectHandler::new( let mut body_handler = TransmitBodyConnectHandler::new(
trusted_stream, trusted_stream,
task_source, task_source,
canceller,
chunk_request_sender.clone(), chunk_request_sender.clone(),
in_memory, in_memory,
source, source,

View file

@ -110,22 +110,17 @@ impl AnalyserNode {
) -> Fallible<DomRoot<AnalyserNode>> { ) -> Fallible<DomRoot<AnalyserNode>> {
let (node, recv) = AnalyserNode::new_inherited(window, context, options)?; let (node, recv) = AnalyserNode::new_inherited(window, context, options)?;
let object = reflect_dom_object_with_proto(Box::new(node), window, proto, can_gc); let object = reflect_dom_object_with_proto(Box::new(node), window, proto, can_gc);
let (source, canceller) = window let task_source = window.task_manager().dom_manipulation_task_source();
.task_manager()
.dom_manipulation_task_source_with_canceller();
let this = Trusted::new(&*object); let this = Trusted::new(&*object);
ROUTER.add_typed_route( ROUTER.add_typed_route(
recv, recv,
Box::new(move |block| { Box::new(move |block| {
let this = this.clone(); let this = this.clone();
let _ = source.queue_with_canceller( let _ = task_source.queue(task!(append_analysis_block: move || {
task!(append_analysis_block: move || { let this = this.root();
let this = this.root(); this.push_block(block.unwrap())
this.push_block(block.unwrap()) }));
}),
&canceller,
);
}), }),
); );
Ok(object) Ok(object)

View file

@ -157,8 +157,7 @@ impl AudioContextMethods<crate::DomTypeHolder> for AudioContext {
} }
// Steps 4 and 5. // Steps 4 and 5.
let window = DomRoot::downcast::<Window>(self.global()).unwrap(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let task_source = window.task_manager().dom_manipulation_task_source();
let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_promise = TrustedPromise::new(promise.clone());
match self.context.audio_context_impl().lock().unwrap().suspend() { match self.context.audio_context_impl().lock().unwrap().suspend() {
Ok(_) => { Ok(_) => {
@ -172,27 +171,21 @@ impl AudioContextMethods<crate::DomTypeHolder> for AudioContext {
promise.resolve_native(&()); promise.resolve_native(&());
if base_context.State() != AudioContextState::Suspended { if base_context.State() != AudioContextState::Suspended {
base_context.set_state_attribute(AudioContextState::Suspended); base_context.set_state_attribute(AudioContextState::Suspended);
let window = DomRoot::downcast::<Window>(context.global()).unwrap(); context.global().task_manager().dom_manipulation_task_source().queue_simple_event(
window.task_manager().dom_manipulation_task_source().queue_simple_event(
context.upcast(), context.upcast(),
atom!("statechange"), atom!("statechange"),
&window );
);
} }
}), })
window.upcast(),
); );
}, },
Err(_) => { Err(_) => {
// The spec does not define the error case and `suspend` should // The spec does not define the error case and `suspend` should
// never fail, but we handle the case here for completion. // never fail, but we handle the case here for completion.
let _ = task_source.queue( let _ = task_source.queue(task!(suspend_error: move || {
task!(suspend_error: move || { let promise = trusted_promise.root();
let promise = trusted_promise.root(); promise.reject_error(Error::Type("Something went wrong".to_owned()));
promise.reject_error(Error::Type("Something went wrong".to_owned())); }));
}),
window.upcast(),
);
}, },
}; };
@ -218,8 +211,7 @@ impl AudioContextMethods<crate::DomTypeHolder> for AudioContext {
} }
// Steps 4 and 5. // Steps 4 and 5.
let window = DomRoot::downcast::<Window>(self.global()).unwrap(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let task_source = window.task_manager().dom_manipulation_task_source();
let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_promise = TrustedPromise::new(promise.clone());
match self.context.audio_context_impl().lock().unwrap().close() { match self.context.audio_context_impl().lock().unwrap().close() {
Ok(_) => { Ok(_) => {
@ -233,27 +225,21 @@ impl AudioContextMethods<crate::DomTypeHolder> for AudioContext {
promise.resolve_native(&()); promise.resolve_native(&());
if base_context.State() != AudioContextState::Closed { if base_context.State() != AudioContextState::Closed {
base_context.set_state_attribute(AudioContextState::Closed); base_context.set_state_attribute(AudioContextState::Closed);
let window = DomRoot::downcast::<Window>(context.global()).unwrap(); context.global().task_manager().dom_manipulation_task_source().queue_simple_event(
window.task_manager().dom_manipulation_task_source().queue_simple_event(
context.upcast(), context.upcast(),
atom!("statechange"), atom!("statechange"),
&window );
);
} }
}), })
window.upcast(),
); );
}, },
Err(_) => { Err(_) => {
// The spec does not define the error case and `suspend` should // The spec does not define the error case and `suspend` should
// never fail, but we handle the case here for completion. // never fail, but we handle the case here for completion.
let _ = task_source.queue( let _ = task_source.queue(task!(suspend_error: move || {
task!(suspend_error: move || { let promise = trusted_promise.root();
let promise = trusted_promise.root(); promise.reject_error(Error::Type("Something went wrong".to_owned()));
promise.reject_error(Error::Type("Something went wrong".to_owned())); }));
}),
window.upcast(),
);
}, },
}; };

View file

@ -71,25 +71,15 @@ impl AudioScheduledSourceNodeMethods<crate::DomTypeHolder> for AudioScheduledSou
} }
let this = Trusted::new(self); let this = Trusted::new(self);
let global = self.global(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let window = global.as_window();
let (task_source, canceller) = window
.task_manager()
.dom_manipulation_task_source_with_canceller();
let callback = OnEndedCallback::new(move || { let callback = OnEndedCallback::new(move || {
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(ended: move || {
task!(ended: move || { let this = this.root();
let this = this.root(); this.global().task_manager().dom_manipulation_task_source().queue_simple_event(
let global = this.global(); this.upcast(),
let window = global.as_window(); atom!("ended"),
window.task_manager().dom_manipulation_task_source().queue_simple_event( );
this.upcast(), }));
atom!("ended"),
window
);
}),
&canceller,
);
}); });
self.node() self.node()

View file

@ -89,18 +89,11 @@ impl AudioTrackList {
// Queue a task to fire an event named change. // Queue a task to fire an event named change.
let global = &self.global(); let global = &self.global();
let this = Trusted::new(self); let this = Trusted::new(self);
let (source, canceller) = global let task_source = global.task_manager().media_element_task_source();
.as_window() let _ = task_source.queue(task!(media_track_change: move || {
.task_manager() let this = this.root();
.media_element_task_source_with_canceller(); this.upcast::<EventTarget>().fire_event(atom!("change"), CanGc::note());
}));
let _ = source.queue_with_canceller(
task!(media_track_change: move || {
let this = this.root();
this.upcast::<EventTarget>().fire_event(atom!("change"), CanGc::note());
}),
&canceller,
);
} }
pub fn add(&self, track: &AudioTrack) { pub fn add(&self, track: &AudioTrack) {

View file

@ -65,7 +65,6 @@ use crate::dom::oscillatornode::OscillatorNode;
use crate::dom::pannernode::PannerNode; use crate::dom::pannernode::PannerNode;
use crate::dom::promise::Promise; use crate::dom::promise::Promise;
use crate::dom::stereopannernode::StereoPannerNode; use crate::dom::stereopannernode::StereoPannerNode;
use crate::dom::window::Window;
use crate::realms::InRealm; use crate::realms::InRealm;
use crate::script_runtime::CanGc; use crate::script_runtime::CanGc;
@ -230,9 +229,7 @@ impl BaseAudioContext {
} }
pub fn resume(&self) { pub fn resume(&self) {
let global = self.global(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let window = global.as_window();
let task_source = window.task_manager().dom_manipulation_task_source();
let this = Trusted::new(self); let this = Trusted::new(self);
// Set the rendering thread state to 'running' and start // Set the rendering thread state to 'running' and start
// rendering the audio graph. // rendering the audio graph.
@ -245,28 +242,22 @@ impl BaseAudioContext {
this.fulfill_in_flight_resume_promises(|| { this.fulfill_in_flight_resume_promises(|| {
if this.state.get() != AudioContextState::Running { if this.state.get() != AudioContextState::Running {
this.state.set(AudioContextState::Running); this.state.set(AudioContextState::Running);
let window = DomRoot::downcast::<Window>(this.global()).unwrap(); this.global().task_manager().dom_manipulation_task_source().queue_simple_event(
window.task_manager().dom_manipulation_task_source().queue_simple_event(
this.upcast(), this.upcast(),
atom!("statechange"), atom!("statechange"),
&window
); );
} }
}); });
}), })
window.upcast(),
); );
}, },
Err(()) => { Err(()) => {
self.take_pending_resume_promises(Err(Error::Type( self.take_pending_resume_promises(Err(Error::Type(
"Something went wrong".to_owned(), "Something went wrong".to_owned(),
))); )));
let _ = task_source.queue( let _ = task_source.queue(task!(resume_error: move || {
task!(resume_error: move || { this.root().fulfill_in_flight_resume_promises(|| {})
this.root().fulfill_in_flight_resume_promises(|| {}) }));
}),
window.upcast(),
);
}, },
} }
} }
@ -485,8 +476,6 @@ impl BaseAudioContextMethods<crate::DomTypeHolder> for BaseAudioContext {
) -> Rc<Promise> { ) -> Rc<Promise> {
// Step 1. // Step 1.
let promise = Promise::new_in_current_realm(comp, can_gc); let promise = Promise::new_in_current_realm(comp, can_gc);
let global = self.global();
let window = global.as_window();
if audio_data.len() > 0 { if audio_data.len() > 0 {
// Step 2. // Step 2.
@ -512,12 +501,8 @@ impl BaseAudioContextMethods<crate::DomTypeHolder> for BaseAudioContext {
let channels = Arc::new(Mutex::new(HashMap::new())); let channels = Arc::new(Mutex::new(HashMap::new()));
let this = Trusted::new(self); let this = Trusted::new(self);
let this_ = this.clone(); let this_ = this.clone();
let (task_source, canceller) = window let task_source = self.global().task_manager().dom_manipulation_task_source();
.task_manager() let task_source_clone = task_source.clone();
.dom_manipulation_task_source_with_canceller();
let (task_source_, canceller_) = window
.task_manager()
.dom_manipulation_task_source_with_canceller();
let callbacks = AudioDecoderCallbacks::new() let callbacks = AudioDecoderCallbacks::new()
.ready(move |channel_count| { .ready(move |channel_count| {
decoded_audio decoded_audio
@ -538,36 +523,32 @@ impl BaseAudioContextMethods<crate::DomTypeHolder> for BaseAudioContext {
decoded_audio[channel].extend_from_slice((*buffer).as_ref()); decoded_audio[channel].extend_from_slice((*buffer).as_ref());
}) })
.eos(move || { .eos(move || {
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(audio_decode_eos: move || {
task!(audio_decode_eos: move || { let this = this.root();
let this = this.root(); let decoded_audio = decoded_audio__.lock().unwrap();
let decoded_audio = decoded_audio__.lock().unwrap(); let length = if decoded_audio.len() >= 1 {
let length = if decoded_audio.len() >= 1 { decoded_audio[0].len()
decoded_audio[0].len() } else {
} else { 0
0 };
}; let buffer = AudioBuffer::new(
let buffer = AudioBuffer::new( this.global().as_window(),
this.global().as_window(), decoded_audio.len() as u32 /* number of channels */,
decoded_audio.len() as u32 /* number of channels */, length as u32,
length as u32, this.sample_rate,
this.sample_rate, Some(decoded_audio.as_slice()),
Some(decoded_audio.as_slice()), CanGc::note());
CanGc::note()); let mut resolvers = this.decode_resolvers.borrow_mut();
let mut resolvers = this.decode_resolvers.borrow_mut(); assert!(resolvers.contains_key(&uuid_));
assert!(resolvers.contains_key(&uuid_)); let resolver = resolvers.remove(&uuid_).unwrap();
let resolver = resolvers.remove(&uuid_).unwrap(); if let Some(callback) = resolver.success_callback {
if let Some(callback) = resolver.success_callback { let _ = callback.Call__(&buffer, ExceptionHandling::Report);
let _ = callback.Call__(&buffer, ExceptionHandling::Report); }
} resolver.promise.resolve_native(&buffer);
resolver.promise.resolve_native(&buffer); }));
}),
&canceller,
);
}) })
.error(move |error| { .error(move |error| {
let _ = task_source_.queue_with_canceller( let _ = task_source_clone.queue(task!(audio_decode_eos: move || {
task!(audio_decode_eos: move || {
let this = this_.root(); let this = this_.root();
let mut resolvers = this.decode_resolvers.borrow_mut(); let mut resolvers = this.decode_resolvers.borrow_mut();
assert!(resolvers.contains_key(&uuid)); assert!(resolvers.contains_key(&uuid));
@ -579,9 +560,7 @@ impl BaseAudioContextMethods<crate::DomTypeHolder> for BaseAudioContext {
} }
let error = format!("Audio decode error {:?}", error); let error = format!("Audio decode error {:?}", error);
resolver.promise.reject_error(Error::Type(error)); resolver.promise.reject_error(Error::Type(error));
}), }));
&canceller_,
);
}) })
.build(); .build();
self.audio_context_impl self.audio_context_impl

View file

@ -2,7 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::mem::replace;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use std::sync::Arc; use std::sync::Arc;
use std::thread::{self, JoinHandle}; use std::thread::{self, JoinHandle};
@ -76,9 +75,10 @@ impl<'a> AutoWorkerReset<'a> {
workerscope: &'a DedicatedWorkerGlobalScope, workerscope: &'a DedicatedWorkerGlobalScope,
worker: TrustedWorkerAddress, worker: TrustedWorkerAddress,
) -> AutoWorkerReset<'a> { ) -> AutoWorkerReset<'a> {
let old_worker = workerscope.replace_worker(Some(worker));
AutoWorkerReset { AutoWorkerReset {
workerscope, workerscope,
old_worker: replace(&mut *workerscope.worker.borrow_mut(), Some(worker)), old_worker,
} }
} }
} }
@ -86,9 +86,7 @@ impl<'a> AutoWorkerReset<'a> {
impl Drop for AutoWorkerReset<'_> { impl Drop for AutoWorkerReset<'_> {
fn drop(&mut self) { fn drop(&mut self) {
self.workerscope self.workerscope
.worker .replace_worker(std::mem::take(&mut self.old_worker));
.borrow_mut()
.clone_from(&self.old_worker)
} }
} }
@ -387,6 +385,7 @@ impl DedicatedWorkerGlobalScope {
}), }),
pipeline_id, pipeline_id,
name: TaskSourceName::Networking, name: TaskSourceName::Networking,
canceller: Default::default(),
}; };
Runtime::new_with_parent(Some(parent), Some(task_source)) Runtime::new_with_parent(Some(parent), Some(task_source))
}; };
@ -501,15 +500,38 @@ impl DedicatedWorkerGlobalScope {
.expect("Thread spawning failed") .expect("Thread spawning failed")
} }
/// The non-None value of the `worker` field can contain a rooted [`TrustedWorkerAddress`]
/// version of the main thread's worker object. This is set while handling messages and then
/// unset otherwise, ensuring that the main thread object can be garbage collected. See
/// [`AutoWorkerReset`].
fn replace_worker(
&self,
new_worker: Option<TrustedWorkerAddress>,
) -> Option<TrustedWorkerAddress> {
let old_worker = std::mem::replace(&mut *self.worker.borrow_mut(), new_worker);
// The `TaskManager` maintains a handle to this `DedicatedWorkerGlobalScope`'s
// event_loop_sender, which might in turn have a `TrustedWorkerAddress` rooting of the main
// thread's worker, which prevents garbage collection. Resetting it here ensures that
// garbage collection of the main thread object can happen again (assuming the new `worker`
// is `None`).
self.upcast::<GlobalScope>()
.task_manager()
.set_sender(self.event_loop_sender());
old_worker
}
pub fn image_cache(&self) -> Arc<dyn ImageCache> { pub fn image_cache(&self) -> Arc<dyn ImageCache> {
self.image_cache.clone() self.image_cache.clone()
} }
pub fn script_chan(&self) -> Box<dyn ScriptChan + Send> { pub(crate) fn event_loop_sender(&self) -> Option<Box<dyn ScriptChan + Send>> {
Box::new(WorkerThreadWorkerChan { let worker = self.worker.borrow().clone()?;
Some(Box::new(WorkerThreadWorkerChan {
sender: self.own_sender.clone(), sender: self.own_sender.clone(),
worker: self.worker.borrow().as_ref().unwrap().clone(), worker,
}) }))
} }
pub fn new_script_pair(&self) -> (Box<dyn ScriptChan + Send>, Box<dyn ScriptPort + Send>) { pub fn new_script_pair(&self) -> (Box<dyn ScriptChan + Send>, Box<dyn ScriptPort + Send>) {

View file

@ -696,37 +696,34 @@ impl Document {
// But it's now Step 4 in https://html.spec.whatwg.org/multipage/#reactivate-a-document // But it's now Step 4 in https://html.spec.whatwg.org/multipage/#reactivate-a-document
// TODO: See #32687 for more information. // TODO: See #32687 for more information.
let document = Trusted::new(self); let document = Trusted::new(self);
self.window self.window()
.task_manager() .task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue( .queue(task!(fire_pageshow_event: move || {
task!(fire_pageshow_event: move || { let document = document.root();
let document = document.root(); let window = document.window();
let window = document.window(); // Step 4.6.1
// Step 4.6.1 if document.page_showing.get() {
if document.page_showing.get() { return;
return; }
} // Step 4.6.2 Set document's page showing flag to true.
// Step 4.6.2 Set document's page showing flag to true. document.page_showing.set(true);
document.page_showing.set(true); // Step 4.6.3 Update the visibility state of document to "visible".
// Step 4.6.3 Update the visibility state of document to "visible". document.update_visibility_state(DocumentVisibilityState::Visible, CanGc::note());
document.update_visibility_state(DocumentVisibilityState::Visible, CanGc::note()); // Step 4.6.4 Fire a page transition event named pageshow at document's relevant
// Step 4.6.4 Fire a page transition event named pageshow at document's relevant // global object with true.
// global object with true. let event = PageTransitionEvent::new(
let event = PageTransitionEvent::new( window,
window, atom!("pageshow"),
atom!("pageshow"), false, // bubbles
false, // bubbles false, // cancelable
false, // cancelable true, // persisted
true, // persisted CanGc::note(),
CanGc::note(), );
); let event = event.upcast::<Event>();
let event = event.upcast::<Event>(); event.set_trusted(true);
event.set_trusted(true); window.dispatch_event_with_target_override(event, CanGc::note());
window.dispatch_event_with_target_override(event, CanGc::note()); }))
}),
self.window.upcast(),
)
.unwrap(); .unwrap();
} }
@ -2129,14 +2126,9 @@ impl Document {
request: RequestBuilder, request: RequestBuilder,
listener: Listener, listener: Listener,
) { ) {
let (task_source, canceller) = self
.window()
.task_manager()
.networking_task_source_with_canceller();
let callback = NetworkListener { let callback = NetworkListener {
context: std::sync::Arc::new(Mutex::new(listener)), context: std::sync::Arc::new(Mutex::new(listener)),
task_source, task_source: self.window().task_manager().networking_task_source(),
canceller: Some(canceller),
} }
.into_callback(); .into_callback();
self.loader_mut() self.loader_mut()
@ -2149,14 +2141,9 @@ impl Document {
listener: Listener, listener: Listener,
cancel_override: Option<ipc::IpcReceiver<()>>, cancel_override: Option<ipc::IpcReceiver<()>>,
) { ) {
let (task_source, canceller) = self
.window()
.task_manager()
.networking_task_source_with_canceller();
let callback = NetworkListener { let callback = NetworkListener {
context: std::sync::Arc::new(Mutex::new(listener)), context: std::sync::Arc::new(Mutex::new(listener)),
task_source, task_source: self.window().task_manager().networking_task_source(),
canceller: Some(canceller),
} }
.into_callback(); .into_callback();
self.loader_mut() self.loader_mut()
@ -2384,81 +2371,75 @@ impl Document {
// Step 7. // Step 7.
debug!("Document loads are complete."); debug!("Document loads are complete.");
let document = Trusted::new(self); let document = Trusted::new(self);
self.window self.window()
.task_manager() .task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue( .queue(task!(fire_load_event: move || {
task!(fire_load_event: move || { let document = document.root();
let document = document.root(); let window = document.window();
let window = document.window(); if !window.is_alive() {
if !window.is_alive() { return;
return; }
}
// Step 7.1. // Step 7.1.
document.set_ready_state(DocumentReadyState::Complete, CanGc::note()); document.set_ready_state(DocumentReadyState::Complete, CanGc::note());
// Step 7.2. // Step 7.2.
if document.browsing_context().is_none() { if document.browsing_context().is_none() {
return; return;
} }
let event = Event::new( let event = Event::new(
window.upcast(), window.upcast(),
atom!("load"), atom!("load"),
EventBubbles::DoesNotBubble, EventBubbles::DoesNotBubble,
EventCancelable::NotCancelable, EventCancelable::NotCancelable,
CanGc::note(), CanGc::note(),
); );
event.set_trusted(true); event.set_trusted(true);
// http://w3c.github.io/navigation-timing/#widl-PerformanceNavigationTiming-loadEventStart // http://w3c.github.io/navigation-timing/#widl-PerformanceNavigationTiming-loadEventStart
update_with_current_instant(&document.load_event_start); update_with_current_instant(&document.load_event_start);
debug!("About to dispatch load for {:?}", document.url()); debug!("About to dispatch load for {:?}", document.url());
window.dispatch_event_with_target_override(&event, CanGc::note()); window.dispatch_event_with_target_override(&event, CanGc::note());
// http://w3c.github.io/navigation-timing/#widl-PerformanceNavigationTiming-loadEventEnd // http://w3c.github.io/navigation-timing/#widl-PerformanceNavigationTiming-loadEventEnd
update_with_current_instant(&document.load_event_end); update_with_current_instant(&document.load_event_end);
if let Some(fragment) = document.url().fragment() { if let Some(fragment) = document.url().fragment() {
document.check_and_scroll_fragment(fragment, CanGc::note()); document.check_and_scroll_fragment(fragment, CanGc::note());
} }
}), }))
self.window.upcast(),
)
.unwrap(); .unwrap();
// Step 8. // Step 8.
let document = Trusted::new(self); let document = Trusted::new(self);
if document.root().browsing_context().is_some() { if document.root().browsing_context().is_some() {
self.window self.window()
.task_manager() .task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue( .queue(task!(fire_pageshow_event: move || {
task!(fire_pageshow_event: move || { let document = document.root();
let document = document.root(); let window = document.window();
let window = document.window(); if document.page_showing.get() || !window.is_alive() {
if document.page_showing.get() || !window.is_alive() { return;
return; }
}
document.page_showing.set(true); document.page_showing.set(true);
let event = PageTransitionEvent::new( let event = PageTransitionEvent::new(
window, window,
atom!("pageshow"), atom!("pageshow"),
false, // bubbles false, // bubbles
false, // cancelable false, // cancelable
false, // persisted false, // persisted
CanGc::note(), CanGc::note(),
); );
let event = event.upcast::<Event>(); let event = event.upcast::<Event>();
event.set_trusted(true); event.set_trusted(true);
window.dispatch_event_with_target_override(event, CanGc::note()); window.dispatch_event_with_target_override(event, CanGc::note());
}), }))
self.window.upcast(),
)
.unwrap(); .unwrap();
} }
@ -2486,32 +2467,29 @@ impl Document {
// TODO: fully implement "completely loaded". // TODO: fully implement "completely loaded".
let document = Trusted::new(self); let document = Trusted::new(self);
if document.root().browsing_context().is_some() { if document.root().browsing_context().is_some() {
self.window self.window()
.task_manager() .task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue( .queue(task!(completely_loaded: move || {
task!(completely_loaded: move || { let document = document.root();
let document = document.root(); document.completely_loaded.set(true);
document.completely_loaded.set(true); if let Some(DeclarativeRefresh::PendingLoad {
if let Some(DeclarativeRefresh::PendingLoad { url,
url, time
time }) = &*document.declarative_refresh.borrow() {
}) = &*document.declarative_refresh.borrow() { // https://html.spec.whatwg.org/multipage/#shared-declarative-refresh-steps
// https://html.spec.whatwg.org/multipage/#shared-declarative-refresh-steps document.window.upcast::<GlobalScope>().schedule_callback(
document.window.upcast::<GlobalScope>().schedule_callback( OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue {
OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue { window: DomRoot::from_ref(document.window()),
window: DomRoot::from_ref(document.window()), url: url.clone(),
url: url.clone(), }),
}), Duration::from_secs(*time),
Duration::from_secs(*time), );
); }
} // Note: this will, among others, result in the "iframe-load-event-steps" being run.
// Note: this will, among others, result in the "iframe-load-event-steps" being run. // https://html.spec.whatwg.org/multipage/#iframe-load-event-steps
// https://html.spec.whatwg.org/multipage/#iframe-load-event-steps document.notify_constellation_load();
document.notify_constellation_load(); }))
}),
self.window.upcast(),
)
.unwrap(); .unwrap();
} }
} }
@ -2657,9 +2635,8 @@ impl Document {
update_with_current_instant(&self.dom_content_loaded_event_start); update_with_current_instant(&self.dom_content_loaded_event_start);
// Step 4.1. // Step 4.1.
let window = self.window();
let document = Trusted::new(self); let document = Trusted::new(self);
window self.window()
.task_manager() .task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue( .queue(
@ -2667,8 +2644,7 @@ impl Document {
let document = document.root(); let document = document.root();
document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"), CanGc::note()); document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"), CanGc::note());
update_with_current_instant(&document.dom_content_loaded_event_end); update_with_current_instant(&document.dom_content_loaded_event_end);
}), })
window.upcast(),
) )
.unwrap(); .unwrap();
@ -2713,8 +2689,9 @@ impl Document {
// Note: the spec says to discard any tasks queued for fetch. // Note: the spec says to discard any tasks queued for fetch.
// This cancels all tasks on the networking task source, which might be too broad. // This cancels all tasks on the networking task source, which might be too broad.
// See https://github.com/whatwg/html/issues/3837 // See https://github.com/whatwg/html/issues/3837
self.window self.window()
.cancel_all_tasks_from_source(TaskSourceName::Networking); .task_manager()
.cancel_pending_tasks_for_source(TaskSourceName::Networking);
// Step 3. // Step 3.
if let Some(parser) = self.get_current_parser() { if let Some(parser) = self.get_current_parser() {

View file

@ -45,7 +45,6 @@ use crate::fetch::{create_a_potential_cors_request, FetchCanceller};
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
use crate::realms::enter_realm; use crate::realms::enter_realm;
use crate::script_runtime::CanGc; use crate::script_runtime::CanGc;
use crate::task_source::TaskSourceName;
use crate::timers::OneshotTimerCallback; use crate::timers::OneshotTimerCallback;
const DEFAULT_RECONNECTION_TIME: Duration = Duration::from_millis(5000); const DEFAULT_RECONNECTION_TIME: Duration = Duration::from_millis(5000);
@ -121,7 +120,6 @@ impl EventSourceContext {
event_source.upcast::<EventTarget>().fire_event(atom!("open"), CanGc::note()); event_source.upcast::<EventTarget>().fire_event(atom!("open"), CanGc::note());
} }
}), }),
&global,
); );
} }
@ -177,7 +175,6 @@ impl EventSourceContext {
// FIXME(nox): Why are errors silenced here? // FIXME(nox): Why are errors silenced here?
let _ = event_source.global().schedule_callback(callback, duration); let _ = event_source.global().schedule_callback(callback, duration);
}), }),
&global,
); );
} }
@ -266,7 +263,6 @@ impl EventSourceContext {
event.root().upcast::<Event>().fire(event_source.upcast(), CanGc::note()); event.root().upcast::<Event>().fire(event_source.upcast(), CanGc::note());
} }
}), }),
&global,
); );
} }
@ -508,7 +504,6 @@ impl EventSource {
event_source.upcast::<EventTarget>().fire_event(atom!("error"), CanGc::note()); event_source.upcast::<EventTarget>().fire_event(atom!("error"), CanGc::note());
} }
}), }),
&global,
); );
} }
@ -606,7 +601,6 @@ impl EventSourceMethods<crate::DomTypeHolder> for EventSource {
let listener = NetworkListener { let listener = NetworkListener {
context: Arc::new(Mutex::new(context)), context: Arc::new(Mutex::new(context)),
task_source: global.task_manager().networking_task_source(), task_source: global.task_manager().networking_task_source(),
canceller: Some(global.task_canceller(TaskSourceName::Networking)),
}; };
ROUTER.add_typed_route( ROUTER.add_typed_route(
action_receiver, action_receiver,

View file

@ -37,7 +37,6 @@ use crate::dom::progressevent::ProgressEvent;
use crate::realms::enter_realm; use crate::realms::enter_realm;
use crate::script_runtime::{CanGc, JSContext}; use crate::script_runtime::{CanGc, JSContext};
use crate::task::TaskOnce; use crate::task::TaskOnce;
use crate::task_source::TaskSourceName;
#[allow(dead_code)] #[allow(dead_code)]
pub enum FileReadingTask { pub enum FileReadingTask {
@ -503,20 +502,27 @@ impl FileReader {
let filereader = Trusted::new(self); let filereader = Trusted::new(self);
let global = self.global(); let global = self.global();
let canceller = global.task_canceller(TaskSourceName::FileReading);
let task_source = global.task_manager().file_reading_task_source(); let task_source = global.task_manager().file_reading_task_source();
// Queue tasks as appropriate. // Queue tasks as appropriate.
let task = FileReadingTask::ProcessRead(filereader.clone(), gen_id); task_source
task_source.queue_with_canceller(task, &canceller).unwrap(); .queue(FileReadingTask::ProcessRead(filereader.clone(), gen_id))
.unwrap();
if !blob_contents.is_empty() { if !blob_contents.is_empty() {
let task = FileReadingTask::ProcessReadData(filereader.clone(), gen_id); task_source
task_source.queue_with_canceller(task, &canceller).unwrap(); .queue(FileReadingTask::ProcessReadData(filereader.clone(), gen_id))
.unwrap();
} }
let task = FileReadingTask::ProcessReadEOF(filereader, gen_id, load_data, blob_contents); task_source
task_source.queue_with_canceller(task, &canceller).unwrap(); .queue(FileReadingTask::ProcessReadEOF(
filereader,
gen_id,
load_data,
blob_contents,
))
.unwrap();
Ok(()) Ok(())
} }

View file

@ -27,11 +27,9 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise; use crate::dom::promise::Promise;
use crate::realms::InRealm; use crate::realms::InRealm;
use crate::script_runtime::{CanGc, JSContext}; use crate::script_runtime::{CanGc, JSContext};
use crate::task::TaskCanceller; use crate::task_source::TaskSource;
use crate::task_source::{TaskSource, TaskSourceName};
struct HapticEffectListener { struct HapticEffectListener {
canceller: TaskCanceller,
task_source: TaskSource, task_source: TaskSource,
context: Trusted<GamepadHapticActuator>, context: Trusted<GamepadHapticActuator>,
} }
@ -39,24 +37,22 @@ struct HapticEffectListener {
impl HapticEffectListener { impl HapticEffectListener {
fn handle_stopped(&self, stopped_successfully: bool) { fn handle_stopped(&self, stopped_successfully: bool) {
let context = self.context.clone(); let context = self.context.clone();
let _ = self.task_source.queue_with_canceller( let _ = self
task!(handle_haptic_effect_stopped: move || { .task_source
.queue(task!(handle_haptic_effect_stopped: move || {
let actuator = context.root(); let actuator = context.root();
actuator.handle_haptic_effect_stopped(stopped_successfully); actuator.handle_haptic_effect_stopped(stopped_successfully);
}), }));
&self.canceller,
);
} }
fn handle_completed(&self, completed_successfully: bool) { fn handle_completed(&self, completed_successfully: bool) {
let context = self.context.clone(); let context = self.context.clone();
let _ = self.task_source.queue_with_canceller( let _ = self
task!(handle_haptic_effect_completed: move || { .task_source
.queue(task!(handle_haptic_effect_completed: move || {
let actuator = context.root(); let actuator = context.root();
actuator.handle_haptic_effect_completed(completed_successfully); actuator.handle_haptic_effect_completed(completed_successfully);
}), }));
&self.canceller,
);
} }
} }
@ -204,7 +200,6 @@ impl GamepadHapticActuatorMethods<crate::DomTypeHolder> for GamepadHapticActuato
let message = DOMString::from("preempted"); let message = DOMString::from("preempted");
promise.resolve_native(&message); promise.resolve_native(&message);
}), }),
&self.global(),
); );
} }
@ -219,13 +214,8 @@ impl GamepadHapticActuatorMethods<crate::DomTypeHolder> for GamepadHapticActuato
let context = Trusted::new(self); let context = Trusted::new(self);
let (effect_complete_sender, effect_complete_receiver) = let (effect_complete_sender, effect_complete_receiver) =
ipc::channel().expect("ipc channel failure"); ipc::channel().expect("ipc channel failure");
let (task_source, canceller) = (
self.global().task_manager().gamepad_task_source(),
self.global().task_canceller(TaskSourceName::Gamepad),
);
let listener = HapticEffectListener { let listener = HapticEffectListener {
canceller, task_source: self.global().task_manager().gamepad_task_source(),
task_source,
context, context,
}; };
@ -277,7 +267,6 @@ impl GamepadHapticActuatorMethods<crate::DomTypeHolder> for GamepadHapticActuato
let message = DOMString::from("preempted"); let message = DOMString::from("preempted");
promise.resolve_native(&message); promise.resolve_native(&message);
}), }),
&self.global(),
); );
} }
@ -288,13 +277,8 @@ impl GamepadHapticActuatorMethods<crate::DomTypeHolder> for GamepadHapticActuato
let context = Trusted::new(self); let context = Trusted::new(self);
let (effect_stop_sender, effect_stop_receiver) = let (effect_stop_sender, effect_stop_receiver) =
ipc::channel().expect("ipc channel failure"); ipc::channel().expect("ipc channel failure");
let (task_source, canceller) = (
self.global().task_manager().gamepad_task_source(),
self.global().task_canceller(TaskSourceName::Gamepad),
);
let listener = HapticEffectListener { let listener = HapticEffectListener {
canceller, task_source: self.global().task_manager().gamepad_task_source(),
task_source,
context, context,
}; };
@ -350,8 +334,7 @@ impl GamepadHapticActuator {
let promise = trusted_promise.root(); let promise = trusted_promise.root();
let message = DOMString::from("complete"); let message = DOMString::from("complete");
promise.resolve_native(&message); promise.resolve_native(&message);
}), })
&self.global(),
); );
} }
} }
@ -372,7 +355,6 @@ impl GamepadHapticActuator {
let message = DOMString::from("preempted"); let message = DOMString::from("preempted");
promise.resolve_native(&message); promise.resolve_native(&message);
}), }),
&self.global(),
); );
let (send, _rcv) = ipc::channel().expect("ipc channel failure"); let (send, _rcv) = ipc::channel().expect("ipc channel failure");

View file

@ -70,6 +70,7 @@ use super::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeO
use super::bindings::codegen::Bindings::WebGPUBinding::GPUDeviceLostReason; use super::bindings::codegen::Bindings::WebGPUBinding::GPUDeviceLostReason;
use super::bindings::error::Fallible; use super::bindings::error::Fallible;
use super::bindings::trace::{HashMapTracedValues, RootedTraceableBox}; use super::bindings::trace::{HashMapTracedValues, RootedTraceableBox};
use super::serviceworkerglobalscope::ServiceWorkerGlobalScope;
use crate::dom::bindings::cell::{DomRefCell, RefMut}; use crate::dom::bindings::cell::{DomRefCell, RefMut};
use crate::dom::bindings::codegen::Bindings::BroadcastChannelBinding::BroadcastChannelMethods; use crate::dom::bindings::codegen::Bindings::BroadcastChannelBinding::BroadcastChannelMethods;
use crate::dom::bindings::codegen::Bindings::EventSourceBinding::EventSource_Binding::EventSourceMethods; use crate::dom::bindings::codegen::Bindings::EventSourceBinding::EventSource_Binding::EventSourceMethods;
@ -127,7 +128,6 @@ use crate::dom::webgpu::identityhub::IdentityHub;
use crate::dom::window::Window; use crate::dom::window::Window;
use crate::dom::workerglobalscope::WorkerGlobalScope; use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::dom::workletglobalscope::WorkletGlobalScope; use crate::dom::workletglobalscope::WorkletGlobalScope;
use crate::messaging::MainThreadScriptChan;
use crate::microtask::{Microtask, MicrotaskQueue, UserMicrotask}; use crate::microtask::{Microtask, MicrotaskQueue, UserMicrotask};
use crate::network_listener::{NetworkListener, PreInvoke}; use crate::network_listener::{NetworkListener, PreInvoke};
use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; use crate::realms::{enter_realm, AlreadyInRealm, InRealm};
@ -137,9 +137,8 @@ use crate::script_runtime::{
}; };
use crate::script_thread::{with_script_thread, ScriptThread}; use crate::script_thread::{with_script_thread, ScriptThread};
use crate::security_manager::CSPViolationReporter; use crate::security_manager::CSPViolationReporter;
use crate::task::TaskCanceller;
use crate::task_manager::TaskManager; use crate::task_manager::TaskManager;
use crate::task_source::{TaskSource, TaskSourceName}; use crate::task_source::TaskSource;
use crate::timers::{ use crate::timers::{
IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback, IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback,
}; };
@ -195,6 +194,9 @@ pub struct GlobalScope {
eventtarget: EventTarget, eventtarget: EventTarget,
crypto: MutNullableDom<Crypto>, crypto: MutNullableDom<Crypto>,
/// A [`TaskManager`] for this [`GlobalScope`].
task_manager: OnceCell<TaskManager>,
/// The message-port router id for this global, if it is managing ports. /// The message-port router id for this global, if it is managing ports.
message_port_state: DomRefCell<MessagePortState>, message_port_state: DomRefCell<MessagePortState>,
@ -374,14 +376,12 @@ pub struct GlobalScope {
/// A wrapper for glue-code between the ipc router and the event-loop. /// A wrapper for glue-code between the ipc router and the event-loop.
struct MessageListener { struct MessageListener {
canceller: TaskCanceller,
task_source: TaskSource, task_source: TaskSource,
context: Trusted<GlobalScope>, context: Trusted<GlobalScope>,
} }
/// A wrapper for broadcasts coming in over IPC, and the event-loop. /// A wrapper for broadcasts coming in over IPC, and the event-loop.
struct BroadcastListener { struct BroadcastListener {
canceller: TaskCanceller,
task_source: TaskSource, task_source: TaskSource,
context: Trusted<GlobalScope>, context: Trusted<GlobalScope>,
} }
@ -389,7 +389,6 @@ struct BroadcastListener {
/// A wrapper between timer events coming in over IPC, and the event-loop. /// A wrapper between timer events coming in over IPC, and the event-loop.
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct TimerListener { pub(crate) struct TimerListener {
canceller: TaskCanceller,
task_source: TaskSource, task_source: TaskSource,
context: Trusted<GlobalScope>, context: Trusted<GlobalScope>,
} }
@ -403,7 +402,6 @@ struct FileListener {
/// - Some(Empty) => None /// - Some(Empty) => None
state: Option<FileListenerState>, state: Option<FileListenerState>,
task_source: TaskSource, task_source: TaskSource,
task_canceller: TaskCanceller,
} }
enum FileListenerTarget { enum FileListenerTarget {
@ -516,15 +514,14 @@ impl BroadcastListener {
// This however seems to be hard to avoid in the light of the IPC. // This however seems to be hard to avoid in the light of the IPC.
// One can imagine queueing tasks directly, // One can imagine queueing tasks directly,
// for channels that would be in the same script-thread. // for channels that would be in the same script-thread.
let _ = self.task_source.queue_with_canceller( let _ = self
task!(broadcast_message_event: move || { .task_source
.queue(task!(broadcast_message_event: move || {
let global = context.root(); let global = context.root();
// Step 10 of https://html.spec.whatwg.org/multipage/#dom-broadcastchannel-postmessage, // Step 10 of https://html.spec.whatwg.org/multipage/#dom-broadcastchannel-postmessage,
// For each BroadcastChannel object destination in destinations, queue a task. // For each BroadcastChannel object destination in destinations, queue a task.
global.broadcast_message_event(event, None); global.broadcast_message_event(event, None);
}), }));
&self.canceller,
);
} }
} }
@ -535,7 +532,7 @@ impl TimerListener {
let context = self.context.clone(); let context = self.context.clone();
// Step 18, queue a task, // Step 18, queue a task,
// https://html.spec.whatwg.org/multipage/#timer-initialisation-steps // https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
let _ = self.task_source.queue_with_canceller( let _ = self.task_source.queue(
task!(timer_event: move || { task!(timer_event: move || {
let global = context.root(); let global = context.root();
let TimerEvent(source, id) = event; let TimerEvent(source, id) = event;
@ -550,8 +547,7 @@ impl TimerListener {
}; };
// Step 7, substeps run in a task. // Step 7, substeps run in a task.
global.fire_timer(id, CanGc::note()); global.fire_timer(id, CanGc::note());
}), })
&self.canceller,
); );
} }
@ -568,7 +564,7 @@ impl MessageListener {
match msg { match msg {
MessagePortMsg::CompleteTransfer(ports) => { MessagePortMsg::CompleteTransfer(ports) => {
let context = self.context.clone(); let context = self.context.clone();
let _ = self.task_source.queue_with_canceller( let _ = self.task_source.queue(
task!(process_complete_transfer: move || { task!(process_complete_transfer: move || {
let global = context.root(); let global = context.root();
@ -598,39 +594,31 @@ impl MessageListener {
let _ = global.script_to_constellation_chan().send( let _ = global.script_to_constellation_chan().send(
ScriptMsg::MessagePortTransferResult(Some(router_id), succeeded, failed), ScriptMsg::MessagePortTransferResult(Some(router_id), succeeded, failed),
); );
}), })
&self.canceller,
); );
}, },
MessagePortMsg::CompletePendingTransfer(port_id, buffer) => { MessagePortMsg::CompletePendingTransfer(port_id, buffer) => {
let context = self.context.clone(); let context = self.context.clone();
let _ = self.task_source.queue_with_canceller( let _ = self.task_source.queue(task!(complete_pending: move || {
task!(complete_pending: move || { let global = context.root();
let global = context.root(); global.complete_port_transfer(port_id, buffer);
global.complete_port_transfer(port_id, buffer); }));
}),
&self.canceller,
);
}, },
MessagePortMsg::NewTask(port_id, task) => { MessagePortMsg::NewTask(port_id, task) => {
let context = self.context.clone(); let context = self.context.clone();
let _ = self.task_source.queue_with_canceller( let _ = self.task_source.queue(task!(process_new_task: move || {
task!(process_new_task: move || { let global = context.root();
let global = context.root(); global.route_task_to_port(port_id, task, CanGc::note());
global.route_task_to_port(port_id, task, CanGc::note()); }));
}),
&self.canceller,
);
}, },
MessagePortMsg::RemoveMessagePort(port_id) => { MessagePortMsg::RemoveMessagePort(port_id) => {
let context = self.context.clone(); let context = self.context.clone();
let _ = self.task_source.queue_with_canceller( let _ = self
task!(process_remove_message_port: move || { .task_source
.queue(task!(process_remove_message_port: move || {
let global = context.root(); let global = context.root();
global.note_entangled_port_removed(&port_id); global.note_entangled_port_removed(&port_id);
}), }));
&self.canceller,
);
}, },
} }
} }
@ -665,10 +653,8 @@ impl FileListener {
let stream = trusted.root(); let stream = trusted.root();
stream_handle_incoming(&stream, Ok(blob_buf.bytes)); stream_handle_incoming(&stream, Ok(blob_buf.bytes));
}); });
let _ = self.task_source.queue(task);
let _ = self
.task_source
.queue_with_canceller(task, &self.task_canceller);
Vec::with_capacity(0) Vec::with_capacity(0)
} else { } else {
blob_buf.bytes blob_buf.bytes
@ -690,9 +676,7 @@ impl FileListener {
stream_handle_incoming(&stream, Ok(bytes_in)); stream_handle_incoming(&stream, Ok(bytes_in));
}); });
let _ = self let _ = self.task_source.queue(task);
.task_source
.queue_with_canceller(task, &self.task_canceller);
} else { } else {
bytes.append(&mut bytes_in); bytes.append(&mut bytes_in);
}; };
@ -712,9 +696,7 @@ impl FileListener {
callback(promise, Ok(bytes)); callback(promise, Ok(bytes));
}); });
let _ = self let _ = self.task_source.queue(task);
.task_source
.queue_with_canceller(task, &self.task_canceller);
}, },
FileListenerTarget::Stream(trusted_stream) => { FileListenerTarget::Stream(trusted_stream) => {
let trusted = trusted_stream.clone(); let trusted = trusted_stream.clone();
@ -724,9 +706,7 @@ impl FileListener {
stream_handle_eof(&stream); stream_handle_eof(&stream);
}); });
let _ = self let _ = self.task_source.queue(task);
.task_source
.queue_with_canceller(task, &self.task_canceller);
}, },
}, },
_ => { _ => {
@ -740,23 +720,17 @@ impl FileListener {
match target { match target {
FileListenerTarget::Promise(trusted_promise, callback) => { FileListenerTarget::Promise(trusted_promise, callback) => {
let _ = self.task_source.queue_with_canceller( let _ = self.task_source.queue(task!(reject_promise: move || {
task!(reject_promise: move || { let promise = trusted_promise.root();
let promise = trusted_promise.root(); let _ac = enter_realm(&*promise.global());
let _ac = enter_realm(&*promise.global()); callback(promise, error);
callback(promise, error); }));
}),
&self.task_canceller,
);
}, },
FileListenerTarget::Stream(trusted_stream) => { FileListenerTarget::Stream(trusted_stream) => {
let _ = self.task_source.queue_with_canceller( let _ = self.task_source.queue(task!(error_stream: move || {
task!(error_stream: move || { let stream = trusted_stream.root();
let stream = trusted_stream.root(); stream_handle_incoming(&stream, error);
stream_handle_incoming(&stream, error); }));
}),
&self.task_canceller,
);
}, },
} }
}, },
@ -785,6 +759,7 @@ impl GlobalScope {
unminify_js: bool, unminify_js: bool,
) -> Self { ) -> Self {
Self { Self {
task_manager: Default::default(),
message_port_state: DomRefCell::new(MessagePortState::UnManaged), message_port_state: DomRefCell::new(MessagePortState::UnManaged),
broadcast_channel_state: DomRefCell::new(BroadcastChannelState::UnManaged), broadcast_channel_state: DomRefCell::new(BroadcastChannelState::UnManaged),
blob_state: DomRefCell::new(BlobState::UnManaged), blob_state: DomRefCell::new(BlobState::UnManaged),
@ -851,16 +826,11 @@ impl GlobalScope {
fn timers(&self) -> &OneshotTimers { fn timers(&self) -> &OneshotTimers {
self.timers.get_or_init(|| { self.timers.get_or_init(|| {
let (task_source, canceller) = (
self.task_manager().timer_task_source(),
self.task_canceller(TaskSourceName::Timer),
);
OneshotTimers::new( OneshotTimers::new(
self, self,
TimerListener { TimerListener {
context: Trusted::new(self), context: Trusted::new(self),
task_source, task_source: self.task_manager().timer_task_source(),
canceller,
}, },
) )
}) })
@ -1099,7 +1069,6 @@ impl GlobalScope {
let target_global = this.root(); let target_global = this.root();
target_global.route_task_to_port(port_id, task, CanGc::note()); target_global.route_task_to_port(port_id, task, CanGc::note());
}), }),
self,
); );
} }
} }
@ -1148,15 +1117,15 @@ impl GlobalScope {
if let Some(entangled_id) = entangled_port { if let Some(entangled_id) = entangled_port {
// Step 7 // Step 7
let this = Trusted::new(self); let this = Trusted::new(self);
let _ = self.task_manager().port_message_queue().queue( let _ =
task!(post_message: move || { self.task_manager()
let global = this.root(); .port_message_queue()
// Note: we do this in a task, as this will ensure the global and constellation .queue(task!(post_message: move || {
// are aware of any transfer that might still take place in the current task. let global = this.root();
global.route_task_to_port(entangled_id, task, CanGc::note()); // Note: we do this in a task, as this will ensure the global and constellation
}), // are aware of any transfer that might still take place in the current task.
self, global.route_task_to_port(entangled_id, task, CanGc::note());
); }));
} }
} else { } else {
warn!("post_messageport_msg called on a global not managing any ports."); warn!("post_messageport_msg called on a global not managing any ports.");
@ -1273,8 +1242,7 @@ impl GlobalScope {
// Step 10.3, fire an event named messageerror at destination. // Step 10.3, fire an event named messageerror at destination.
MessageEvent::dispatch_error(destination.upcast(), &global, CanGc::note()); MessageEvent::dispatch_error(destination.upcast(), &global, CanGc::note());
} }
}), })
self,
); );
}); });
} }
@ -1438,13 +1406,8 @@ impl GlobalScope {
let (broadcast_control_sender, broadcast_control_receiver) = let (broadcast_control_sender, broadcast_control_receiver) =
ipc::channel().expect("ipc channel failure"); ipc::channel().expect("ipc channel failure");
let context = Trusted::new(self); let context = Trusted::new(self);
let (task_source, canceller) = (
self.task_manager().dom_manipulation_task_source(),
self.task_canceller(TaskSourceName::DOMManipulation),
);
let listener = BroadcastListener { let listener = BroadcastListener {
canceller, task_source: self.task_manager().dom_manipulation_task_source(),
task_source,
context, context,
}; };
ROUTER.add_typed_route( ROUTER.add_typed_route(
@ -1491,13 +1454,8 @@ impl GlobalScope {
let (port_control_sender, port_control_receiver) = let (port_control_sender, port_control_receiver) =
ipc::channel().expect("ipc channel failure"); ipc::channel().expect("ipc channel failure");
let context = Trusted::new(self); let context = Trusted::new(self);
let (task_source, canceller) = (
self.task_manager().port_message_queue(),
self.task_canceller(TaskSourceName::PortMessage),
);
let listener = MessageListener { let listener = MessageListener {
canceller, task_source: self.task_manager().port_message_queue(),
task_source,
context, context,
}; };
ROUTER.add_typed_route( ROUTER.add_typed_route(
@ -1540,7 +1498,6 @@ impl GlobalScope {
let target_global = this.root(); let target_global = this.root();
target_global.maybe_add_pending_ports(); target_global.maybe_add_pending_ports();
}), }),
self,
); );
} else { } else {
// If this is a newly-created port, let the constellation immediately know. // If this is a newly-created port, let the constellation immediately know.
@ -2017,15 +1974,11 @@ impl GlobalScope {
let recv = self.send_msg(file_id); let recv = self.send_msg(file_id);
let trusted_stream = Trusted::new(&*stream.clone()); let trusted_stream = Trusted::new(&*stream.clone());
let task_canceller = self.task_canceller(TaskSourceName::FileReading);
let task_source = self.task_manager().file_reading_task_source();
let mut file_listener = FileListener { let mut file_listener = FileListener {
state: Some(FileListenerState::Empty(FileListenerTarget::Stream( state: Some(FileListenerState::Empty(FileListenerTarget::Stream(
trusted_stream, trusted_stream,
))), ))),
task_source, task_source: self.task_manager().file_reading_task_source(),
task_canceller,
}; };
ROUTER.add_typed_route( ROUTER.add_typed_route(
@ -2042,16 +1995,12 @@ impl GlobalScope {
let recv = self.send_msg(id); let recv = self.send_msg(id);
let trusted_promise = TrustedPromise::new(promise); let trusted_promise = TrustedPromise::new(promise);
let task_canceller = self.task_canceller(TaskSourceName::FileReading);
let task_source = self.task_manager().file_reading_task_source();
let mut file_listener = FileListener { let mut file_listener = FileListener {
state: Some(FileListenerState::Empty(FileListenerTarget::Promise( state: Some(FileListenerState::Empty(FileListenerTarget::Promise(
trusted_promise, trusted_promise,
callback, callback,
))), ))),
task_source, task_source: self.task_manager().file_reading_task_source(),
task_canceller,
}; };
ROUTER.add_typed_route( ROUTER.add_typed_route(
@ -2574,28 +2523,36 @@ impl GlobalScope {
self.resource_threads().sender() self.resource_threads().sender()
} }
/// `ScriptChan` to send messages to the event loop of this global scope. /// A sender to the event loop of this global scope. This either sends to the Worker event loop
pub fn script_chan(&self) -> Box<dyn ScriptChan + Send> { /// or the ScriptThread event loop in the case of a `Window`. This can be `None` for dedicated
/// workers that are not currently handling a message.
pub(crate) fn event_loop_sender(&self) -> Option<Box<dyn ScriptChan + Send>> {
if let Some(window) = self.downcast::<Window>() { if let Some(window) = self.downcast::<Window>() {
return Box::new( Some(window.event_loop_sender())
MainThreadScriptChan(window.main_thread_script_chan().clone()).clone(), } else if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() {
dedicated.event_loop_sender()
} else if let Some(service_worker) = self.downcast::<ServiceWorkerGlobalScope>() {
Some(service_worker.event_loop_sender())
} else {
unreachable!(
"Tried to access event loop sender for incompatible \
GlobalScope (PaintWorklet or DissimilarOriginWindow)"
); );
} }
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.script_chan();
}
unreachable!();
} }
/// The [`TaskManager`] used to schedule tasks for this [`GlobalScope`]. /// A reference to the [`TaskManager`] used to schedule tasks for this [`GlobalScope`].
pub fn task_manager(&self) -> &TaskManager { pub(crate) fn task_manager(&self) -> &TaskManager {
if let Some(window) = self.downcast::<Window>() { let shared_canceller = self
return window.task_manager(); .downcast::<WorkerGlobalScope>()
} .map(WorkerGlobalScope::shared_task_canceller);
if let Some(worker) = self.downcast::<WorkerGlobalScope>() { self.task_manager.get_or_init(|| {
return worker.task_manager(); TaskManager::new(
} self.event_loop_sender(),
unreachable!(); self.pipeline_id(),
shared_canceller,
)
})
} }
/// Evaluate JS code on this global scope. /// Evaluate JS code on this global scope.
@ -2777,7 +2734,7 @@ impl GlobalScope {
); );
self.task_manager() self.task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue(task, self) .queue(task)
.unwrap(); .unwrap();
} }
} }
@ -2894,21 +2851,6 @@ impl GlobalScope {
true true
} }
/// Returns the task canceller of this global to ensure that everything is
/// properly cancelled when the global scope is destroyed.
pub fn task_canceller(&self, name: TaskSourceName) -> TaskCanceller {
if let Some(window) = self.downcast::<Window>() {
return window.task_manager().task_canceller(name);
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
// Note: the "name" is not passed to the worker,
// because 'closing' it only requires one task canceller for all task sources.
// https://html.spec.whatwg.org/multipage/#dom-workerglobalscope-closing
return worker.task_canceller();
}
unreachable!();
}
/// Perform a microtask checkpoint. /// Perform a microtask checkpoint.
pub fn perform_a_microtask_checkpoint(&self, can_gc: CanGc) { 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.
@ -3163,29 +3105,26 @@ impl GlobalScope {
let this = Trusted::new(self); let this = Trusted::new(self);
self.task_manager() self.task_manager()
.gamepad_task_source() .gamepad_task_source()
.queue_with_canceller( .queue(task!(gamepad_connected: move || {
task!(gamepad_connected: move || { let global = this.root();
let global = this.root();
if let Some(window) = global.downcast::<Window>() { if let Some(window) = global.downcast::<Window>() {
let navigator = window.Navigator(); let navigator = window.Navigator();
let selected_index = navigator.select_gamepad_index(); let selected_index = navigator.select_gamepad_index();
let gamepad = Gamepad::new( let gamepad = Gamepad::new(
&global, &global,
selected_index, selected_index,
name, name,
"standard".into(), "standard".into(),
axis_bounds, axis_bounds,
button_bounds, button_bounds,
supported_haptic_effects, supported_haptic_effects,
false, false,
CanGc::note(), CanGc::note(),
); );
navigator.set_gamepad(selected_index as usize, &gamepad, CanGc::note()); navigator.set_gamepad(selected_index as usize, &gamepad, CanGc::note());
} }
}), }))
&self.task_canceller(TaskSourceName::Gamepad),
)
.expect("Failed to queue gamepad connected task."); .expect("Failed to queue gamepad connected task.");
} }
@ -3194,21 +3133,18 @@ impl GlobalScope {
let this = Trusted::new(self); let this = Trusted::new(self);
self.task_manager() self.task_manager()
.gamepad_task_source() .gamepad_task_source()
.queue_with_canceller( .queue(task!(gamepad_disconnected: move || {
task!(gamepad_disconnected: move || { let global = this.root();
let global = this.root(); if let Some(window) = global.downcast::<Window>() {
if let Some(window) = global.downcast::<Window>() { let navigator = window.Navigator();
let navigator = window.Navigator(); if let Some(gamepad) = navigator.get_gamepad(index) {
if let Some(gamepad) = navigator.get_gamepad(index) { if window.Document().is_fully_active() {
if window.Document().is_fully_active() { gamepad.update_connected(false, gamepad.exposed(), CanGc::note());
gamepad.update_connected(false, gamepad.exposed(), CanGc::note()); navigator.remove_gamepad(index);
navigator.remove_gamepad(index);
}
} }
} }
}), }
&self.task_canceller(TaskSourceName::Gamepad), }))
)
.expect("Failed to queue gamepad disconnected task."); .expect("Failed to queue gamepad disconnected task.");
} }
@ -3217,9 +3153,7 @@ impl GlobalScope {
let this = Trusted::new(self); let this = Trusted::new(self);
// <https://w3c.github.io/gamepad/#dfn-update-gamepad-state> // <https://w3c.github.io/gamepad/#dfn-update-gamepad-state>
self.task_manager() self.task_manager().gamepad_task_source().queue(
.gamepad_task_source()
.queue_with_canceller(
task!(update_gamepad_state: move || { task!(update_gamepad_state: move || {
let global = this.root(); let global = this.root();
if let Some(window) = global.downcast::<Window>() { if let Some(window) = global.downcast::<Window>() {
@ -3245,13 +3179,11 @@ impl GlobalScope {
gamepad.update_timestamp(*current_time); gamepad.update_timestamp(*current_time);
let new_gamepad = Trusted::new(&**gamepad); let new_gamepad = Trusted::new(&**gamepad);
if window.Document().is_fully_active() { if window.Document().is_fully_active() {
window.task_manager().gamepad_task_source().queue_with_canceller( global.task_manager().gamepad_task_source().queue(
task!(update_gamepad_connect: move || { task!(update_gamepad_connect: move || {
let gamepad = new_gamepad.root(); let gamepad = new_gamepad.root();
gamepad.notify_event(GamepadEventType::Connected, CanGc::note()); gamepad.notify_event(GamepadEventType::Connected, CanGc::note());
}), })
&window.upcast::<GlobalScope>()
.task_canceller(TaskSourceName::Gamepad),
) )
.expect("Failed to queue update gamepad connect task."); .expect("Failed to queue update gamepad connect task.");
} }
@ -3259,8 +3191,7 @@ impl GlobalScope {
} }
} }
} }
}), })
&self.task_canceller(TaskSourceName::Gamepad),
) )
.expect("Failed to queue update gamepad state task."); .expect("Failed to queue update gamepad state task.");
} }
@ -3333,11 +3264,9 @@ impl GlobalScope {
task_source: TaskSource, task_source: TaskSource,
cancellation_sender: Option<ipc::IpcReceiver<()>>, cancellation_sender: Option<ipc::IpcReceiver<()>>,
) { ) {
let canceller = Some(self.task_canceller(TaskSourceName::Networking));
let network_listener = NetworkListener { let network_listener = NetworkListener {
context, context,
task_source, task_source,
canceller,
}; };
self.fetch_with_network_listener(request_builder, network_listener, cancellation_sender); self.fetch_with_network_listener(request_builder, network_listener, cancellation_sender);
} }

View file

@ -92,7 +92,6 @@ impl VirtualMethods for HTMLDetailsElement {
this.upcast::<EventTarget>().fire_event(atom!("toggle"), CanGc::note()); this.upcast::<EventTarget>().fire_event(atom!("toggle"), CanGc::note());
} }
}), }),
window.upcast(),
); );
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage) self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage)
} }

View file

@ -122,6 +122,6 @@ impl HTMLDialogElementMethods<crate::DomTypeHolder> for HTMLDialogElement {
// Step 5 // Step 5
win.task_manager() win.task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue_simple_event(target, atom!("close"), &win); .queue_simple_event(target, atom!("close"));
} }
} }

View file

@ -1039,7 +1039,7 @@ impl HTMLFormElement {
target target
.task_manager() .task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue(task, target.upcast()) .queue(task)
.unwrap(); .unwrap();
} }

View file

@ -892,24 +892,21 @@ impl HTMLImageElement {
self.abort_request(State::Broken, ImageRequestPhase::Pending, can_gc); self.abort_request(State::Broken, ImageRequestPhase::Pending, can_gc);
// 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(task!(image_null_source_error: move || {
task!(image_null_source_error: move || { let this = this.root();
let this = this.root(); {
{ let mut current_request =
let mut current_request = this.current_request.borrow_mut();
this.current_request.borrow_mut(); current_request.source_url = None;
current_request.source_url = None; current_request.parsed_url = None;
current_request.parsed_url = None; }
} let elem = this.upcast::<Element>();
let elem = this.upcast::<Element>(); let src_present = elem.has_attribute(&local_name!("src"));
let src_present = elem.has_attribute(&local_name!("src"));
if src_present || Self::uses_srcset_or_picture(elem) { if src_present || Self::uses_srcset_or_picture(elem) {
this.upcast::<EventTarget>().fire_event(atom!("error"), CanGc::note()); this.upcast::<EventTarget>().fire_event(atom!("error"), CanGc::note());
} }
}), }));
window.upcast(),
);
return; return;
}, },
}; };
@ -928,19 +925,16 @@ impl HTMLImageElement {
// 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?
let _ = task_source.queue( let _ = task_source.queue(task!(image_selected_source_error: move || {
task!(image_selected_source_error: move || { let this = this.root();
let this = this.root(); {
{ let mut current_request =
let mut current_request = this.current_request.borrow_mut();
this.current_request.borrow_mut(); current_request.source_url = Some(USVString(src))
current_request.source_url = Some(USVString(src)) }
} this.upcast::<EventTarget>().fire_event(atom!("error"), CanGc::note());
this.upcast::<EventTarget>().fire_event(atom!("error"), CanGc::note());
}), }));
window.upcast(),
);
}, },
} }
} }
@ -1021,6 +1015,7 @@ impl HTMLImageElement {
current_request.current_pixel_density = pixel_density; current_request.current_pixel_density = pixel_density;
let this = Trusted::new(self); let this = Trusted::new(self);
let src = src.0; let src = src.0;
let _ = window.task_manager().dom_manipulation_task_source().queue( let _ = window.task_manager().dom_manipulation_task_source().queue(
task!(image_load_event: move || { task!(image_load_event: move || {
let this = this.root(); let this = this.root();
@ -1033,7 +1028,6 @@ impl HTMLImageElement {
// TODO: restart animation, if set. // TODO: restart animation, if set.
this.upcast::<EventTarget>().fire_event(atom!("load"), CanGc::note()); this.upcast::<EventTarget>().fire_event(atom!("load"), CanGc::note());
}), }),
window.upcast(),
); );
return; return;
} }
@ -1069,11 +1063,7 @@ impl HTMLImageElement {
) -> 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();
let task_source = elem.owner_window().task_manager().networking_task_source();
let window = elem.owner_window();
let (task_source, canceller) = window
.task_manager()
.networking_task_source_with_canceller();
let generation = elem.generation.get(); let generation = elem.generation.get();
ROUTER.add_typed_route( ROUTER.add_typed_route(
@ -1085,7 +1075,7 @@ impl HTMLImageElement {
let element = trusted_node.clone(); let element = trusted_node.clone();
let image: PendingImageResponse = message.unwrap(); let image: PendingImageResponse = message.unwrap();
let selected_source_clone = selected_source.clone(); let selected_source_clone = selected_source.clone();
let _ = task_source.queue_with_canceller( let _ = task_source.queue(
task!(process_image_response_for_environment_change: move || { task!(process_image_response_for_environment_change: move || {
let element = element.root(); let element = element.root();
// Ignore any image response for a previous request that has been discarded. // Ignore any image response for a previous request that has been discarded.
@ -1094,8 +1084,7 @@ impl HTMLImageElement {
USVString::from(selected_source_clone), generation, USVString::from(selected_source_clone), generation,
selected_pixel_density, CanGc::note()); selected_pixel_density, CanGc::note());
} }
}), })
&canceller,
); );
}), }),
); );
@ -1283,8 +1272,7 @@ impl HTMLImageElement {
// Step 15.7 // Step 15.7
this.upcast::<EventTarget>().fire_event(atom!("load"), CanGc::note()); this.upcast::<EventTarget>().fire_event(atom!("load"), CanGc::note());
}), })
window.upcast(),
); );
} }

View file

@ -2576,8 +2576,7 @@ impl VirtualMethods for HTMLInputElement {
self.input_type().is_textual_or_password() self.input_type().is_textual_or_password()
{ {
if event.IsTrusted() { if event.IsTrusted() {
let window = self.owner_window(); self.owner_window()
window
.task_manager() .task_manager()
.user_interaction_task_source() .user_interaction_task_source()
.queue_event( .queue_event(
@ -2585,7 +2584,6 @@ impl VirtualMethods for HTMLInputElement {
atom!("input"), atom!("input"),
EventBubbles::Bubbles, EventBubbles::Bubbles,
EventCancelable::NotCancelable, EventCancelable::NotCancelable,
&window,
); );
} }
} else if (event.type_() == atom!("compositionstart") || } else if (event.type_() == atom!("compositionstart") ||

View file

@ -523,11 +523,10 @@ impl HTMLMediaElement {
fn time_marches_on(&self) { fn time_marches_on(&self) {
// Step 6. // Step 6.
if Instant::now() > self.next_timeupdate_event.get() { if Instant::now() > self.next_timeupdate_event.get() {
let window = self.owner_window(); self.owner_window()
window
.task_manager() .task_manager()
.media_element_task_source() .media_element_task_source()
.queue_simple_event(self.upcast(), atom!("timeupdate"), &window); .queue_simple_event(self.upcast(), atom!("timeupdate"));
self.next_timeupdate_event self.next_timeupdate_event
.set(Instant::now() + Duration::from_millis(350)); .set(Instant::now() + Duration::from_millis(350));
} }
@ -547,11 +546,13 @@ impl HTMLMediaElement {
self.take_pending_play_promises(Err(Error::Abort)); self.take_pending_play_promises(Err(Error::Abort));
// Step 2.3. // Step 2.3.
let window = self.owner_window();
let this = Trusted::new(self); let this = Trusted::new(self);
let generation_id = self.generation_id.get(); let generation_id = self.generation_id.get();
let _ = window.task_manager().media_element_task_source().queue( let _ = self
task!(internal_pause_steps: move || { .owner_window()
.task_manager()
.media_element_task_source()
.queue(task!(internal_pause_steps: move || {
let this = this.root(); let this = this.root();
if generation_id != this.generation_id.get() { if generation_id != this.generation_id.get() {
return; return;
@ -574,9 +575,7 @@ impl HTMLMediaElement {
// Done after running this closure in // Done after running this closure in
// `fulfill_in_flight_play_promises`. // `fulfill_in_flight_play_promises`.
}); });
}), }));
window.upcast(),
);
// Step 2.4. // Step 2.4.
// FIXME(nox): Set the official playback position to the current // FIXME(nox): Set the official playback position to the current
@ -594,12 +593,14 @@ impl HTMLMediaElement {
self.take_pending_play_promises(Ok(())); self.take_pending_play_promises(Ok(()));
// Step 2. // Step 2.
let window = self.owner_window();
let this = Trusted::new(self); let this = Trusted::new(self);
let generation_id = self.generation_id.get(); let generation_id = self.generation_id.get();
// FIXME(nox): Why are errors silenced here? // FIXME(nox): Why are errors silenced here?
let _ = window.task_manager().media_element_task_source().queue( let _ = self
task!(notify_about_playing: move || { .owner_window()
.task_manager()
.media_element_task_source()
.queue(task!(notify_about_playing: move || {
let this = this.root(); let this = this.root();
if generation_id != this.generation_id.get() { if generation_id != this.generation_id.get() {
return; return;
@ -615,9 +616,7 @@ impl HTMLMediaElement {
// `fulfill_in_flight_play_promises`. // `fulfill_in_flight_play_promises`.
}); });
}), }));
window.upcast(),
);
} }
// https://html.spec.whatwg.org/multipage/#ready-states // https://html.spec.whatwg.org/multipage/#ready-states
@ -633,13 +632,15 @@ impl HTMLMediaElement {
return; return;
} }
let window = self.owner_window(); let task_source = self
let task_source = window.task_manager().media_element_task_source(); .owner_window()
.task_manager()
.media_element_task_source();
// Step 1. // Step 1.
match (old_ready_state, ready_state) { match (old_ready_state, ready_state) {
(ReadyState::HaveNothing, ReadyState::HaveMetadata) => { (ReadyState::HaveNothing, ReadyState::HaveMetadata) => {
task_source.queue_simple_event(self.upcast(), atom!("loadedmetadata"), &window); task_source.queue_simple_event(self.upcast(), atom!("loadedmetadata"));
// No other steps are applicable in this case. // No other steps are applicable in this case.
return; return;
}, },
@ -648,14 +649,11 @@ impl HTMLMediaElement {
self.fired_loadeddata_event.set(true); self.fired_loadeddata_event.set(true);
let this = Trusted::new(self); let this = Trusted::new(self);
// FIXME(nox): Why are errors silenced here? // FIXME(nox): Why are errors silenced here?
let _ = task_source.queue( let _ = task_source.queue(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"), CanGc::note());
this.upcast::<EventTarget>().fire_event(atom!("loadeddata"), CanGc::note()); this.delay_load_event(false, CanGc::note());
this.delay_load_event(false, CanGc::note()); }));
}),
window.upcast(),
);
} }
// Steps for the transition from HaveMetadata to HaveCurrentData // Steps for the transition from HaveMetadata to HaveCurrentData
@ -676,7 +674,7 @@ impl HTMLMediaElement {
if old_ready_state <= ReadyState::HaveCurrentData && if old_ready_state <= ReadyState::HaveCurrentData &&
ready_state >= ReadyState::HaveFutureData ready_state >= ReadyState::HaveFutureData
{ {
task_source.queue_simple_event(self.upcast(), atom!("canplay"), &window); task_source.queue_simple_event(self.upcast(), atom!("canplay"));
if !self.Paused() { if !self.Paused() {
self.notify_about_playing(); self.notify_about_playing();
@ -697,7 +695,7 @@ impl HTMLMediaElement {
self.time_marches_on(); self.time_marches_on();
} }
// Step 3 // Step 3
task_source.queue_simple_event(self.upcast(), atom!("play"), &window); task_source.queue_simple_event(self.upcast(), atom!("play"));
// Step 4 // Step 4
self.notify_about_playing(); self.notify_about_playing();
// Step 5 // Step 5
@ -706,7 +704,7 @@ impl HTMLMediaElement {
// FIXME(nox): According to the spec, this should come *before* the // FIXME(nox): According to the spec, this should come *before* the
// "play" event. // "play" event.
task_source.queue_simple_event(self.upcast(), atom!("canplaythrough"), &window); task_source.queue_simple_event(self.upcast(), atom!("canplaythrough"));
} }
} }
@ -787,11 +785,10 @@ impl HTMLMediaElement {
self.network_state.set(NetworkState::Loading); self.network_state.set(NetworkState::Loading);
// Step 8. // Step 8.
let window = self.owner_window(); self.owner_window()
window
.task_manager() .task_manager()
.media_element_task_source() .media_element_task_source()
.queue_simple_event(self.upcast(), atom!("loadstart"), &window); .queue_simple_event(self.upcast(), atom!("loadstart"));
// Step 9. // Step 9.
match mode { match mode {
@ -941,19 +938,16 @@ impl HTMLMediaElement {
window window
.task_manager() .task_manager()
.media_element_task_source() .media_element_task_source()
.queue_simple_event(self.upcast(), atom!("suspend"), &window); .queue_simple_event(self.upcast(), atom!("suspend"));
// Step 4.remote.1.3. // Step 4.remote.1.3.
let this = Trusted::new(self); let this = Trusted::new(self);
window window
.task_manager() .task_manager()
.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, CanGc::note());
this.root().delay_load_event(false, CanGc::note()); }))
}),
window.upcast(),
)
.unwrap(); .unwrap();
// Steps 4.remote.1.4. // Steps 4.remote.1.4.
@ -1007,13 +1001,15 @@ impl HTMLMediaElement {
/// ///
/// [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) {
let window = self.owner_window();
let this = Trusted::new(self); let this = Trusted::new(self);
let generation_id = self.generation_id.get(); let generation_id = self.generation_id.get();
self.take_pending_play_promises(Err(Error::NotSupported)); self.take_pending_play_promises(Err(Error::NotSupported));
// FIXME(nox): Why are errors silenced here? // FIXME(nox): Why are errors silenced here?
let _ = window.task_manager().media_element_task_source().queue( let _ = self
task!(dedicated_media_source_failure_steps: move || { .owner_window()
.task_manager()
.media_element_task_source()
.queue(task!(dedicated_media_source_failure_steps: move || {
let this = this.root(); let this = this.root();
if generation_id != this.generation_id.get() { if generation_id != this.generation_id.get() {
return; return;
@ -1052,15 +1048,14 @@ impl HTMLMediaElement {
// Step 7. // Step 7.
this.delay_load_event(false, CanGc::note()); this.delay_load_event(false, CanGc::note());
}), }));
window.upcast(),
);
} }
fn queue_ratechange_event(&self) { fn queue_ratechange_event(&self) {
let window = self.owner_window(); self.owner_window()
let task_source = window.task_manager().media_element_task_source(); .task_manager()
task_source.queue_simple_event(self.upcast(), atom!("ratechange"), &window); .media_element_task_source()
.queue_simple_event(self.upcast(), atom!("ratechange"));
} }
fn in_error_state(&self) -> bool { fn in_error_state(&self) -> bool {
@ -1110,19 +1105,21 @@ impl HTMLMediaElement {
self.fulfill_in_flight_play_promises(|| ()); self.fulfill_in_flight_play_promises(|| ());
} }
let window = self.owner_window(); let task_source = self
let task_source = window.task_manager().media_element_task_source(); .owner_window()
.task_manager()
.media_element_task_source();
// Step 5. // Step 5.
let network_state = self.network_state.get(); let network_state = self.network_state.get();
if network_state == NetworkState::Loading || network_state == NetworkState::Idle { if network_state == NetworkState::Loading || network_state == NetworkState::Idle {
task_source.queue_simple_event(self.upcast(), atom!("abort"), &window); task_source.queue_simple_event(self.upcast(), atom!("abort"));
} }
// Step 6. // Step 6.
if network_state != NetworkState::Empty { if network_state != NetworkState::Empty {
// Step 6.1. // Step 6.1.
task_source.queue_simple_event(self.upcast(), atom!("emptied"), &window); task_source.queue_simple_event(self.upcast(), atom!("emptied"));
// Step 6.2. // Step 6.2.
if let Some(ref mut current_fetch_context) = *self.current_fetch_context.borrow_mut() { if let Some(ref mut current_fetch_context) = *self.current_fetch_context.borrow_mut() {
@ -1160,7 +1157,7 @@ impl HTMLMediaElement {
let queue_timeupdate_event = self.playback_position.get() != 0.; let queue_timeupdate_event = self.playback_position.get() != 0.;
self.playback_position.set(0.); self.playback_position.set(0.);
if queue_timeupdate_event { if queue_timeupdate_event {
task_source.queue_simple_event(self.upcast(), atom!("timeupdate"), &window); task_source.queue_simple_event(self.upcast(), atom!("timeupdate"));
} }
// Step 6.9. // Step 6.9.
@ -1291,9 +1288,10 @@ impl HTMLMediaElement {
// servo-media with gstreamer does not support inaccurate seeking for now. // servo-media with gstreamer does not support inaccurate seeking for now.
// Step 10. // Step 10.
let window = self.owner_window(); self.owner_window()
let task_source = window.task_manager().media_element_task_source(); .task_manager()
task_source.queue_simple_event(self.upcast(), atom!("seeking"), &window); .media_element_task_source()
.queue_simple_event(self.upcast(), atom!("seeking"));
// Step 11. // Step 11.
if let Some(ref player) = *self.player.borrow() { if let Some(ref player) = *self.player.borrow() {
@ -1316,12 +1314,14 @@ impl HTMLMediaElement {
self.time_marches_on(); self.time_marches_on();
// Step 16. // Step 16.
let window = self.owner_window(); let task_source = self
let task_source = window.task_manager().media_element_task_source(); .owner_window()
task_source.queue_simple_event(self.upcast(), atom!("timeupdate"), &window); .task_manager()
.media_element_task_source();
task_source.queue_simple_event(self.upcast(), atom!("timeupdate"));
// Step 17. // Step 17.
task_source.queue_simple_event(self.upcast(), atom!("seeked"), &window); task_source.queue_simple_event(self.upcast(), atom!("seeked"));
} }
/// <https://html.spec.whatwg.org/multipage/#poster-frame> /// <https://html.spec.whatwg.org/multipage/#poster-frame>
@ -1339,9 +1339,10 @@ impl HTMLMediaElement {
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
if pref!(media.testing.enabled) { if pref!(media.testing.enabled) {
let window = self.owner_window(); self.owner_window()
let task_source = window.task_manager().media_element_task_source(); .task_manager()
task_source.queue_simple_event(self.upcast(), atom!("postershown"), &window); .media_element_task_source()
.queue_simple_event(self.upcast(), atom!("postershown"));
} }
} }
@ -1385,21 +1386,16 @@ impl HTMLMediaElement {
*self.player.borrow_mut() = Some(player); *self.player.borrow_mut() = Some(player);
let trusted_node = Trusted::new(self); let trusted_node = Trusted::new(self);
let (task_source, canceller) = window let task_source = window.task_manager().media_element_task_source();
.task_manager()
.media_element_task_source_with_canceller();
ROUTER.add_typed_route( ROUTER.add_typed_route(
action_receiver, action_receiver,
Box::new(move |message| { Box::new(move |message| {
let event = message.unwrap(); let event = message.unwrap();
trace!("Player event {:?}", event); trace!("Player event {:?}", event);
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(task!(handle_player_event: move || {
task!(handle_player_event: move || { this.root().handle_player_event(&event, CanGc::note());
this.root().handle_player_event(&event, CanGc::note()); })) {
}),
&canceller,
) {
warn!("Could not queue player event handler task {:?}", err); warn!("Could not queue player event handler task {:?}", err);
} }
}), }),
@ -1428,42 +1424,37 @@ impl HTMLMediaElement {
if let Some(image_receiver) = image_receiver { if let Some(image_receiver) = image_receiver {
let trusted_node = Trusted::new(self); let trusted_node = Trusted::new(self);
let (task_source, canceller) = window let task_source = window.task_manager().media_element_task_source();
.task_manager()
.media_element_task_source_with_canceller();
ROUTER.add_typed_route( ROUTER.add_typed_route(
image_receiver.to_ipc_receiver(), image_receiver.to_ipc_receiver(),
Box::new(move |message| { Box::new(move |message| {
let msg = message.unwrap(); let msg = message.unwrap();
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(task!(handle_glplayer_message: move || {
task!(handle_glplayer_message: move || { trace!("GLPlayer message {:?}", msg);
trace!("GLPlayer message {:?}", msg); let video_renderer = this.root().video_renderer.clone();
let video_renderer = this.root().video_renderer.clone();
match msg { match msg {
GLPlayerMsgForward::Lock(sender) => { GLPlayerMsgForward::Lock(sender) => {
if let Some(holder) = video_renderer if let Some(holder) = video_renderer
.lock() .lock()
.unwrap() .unwrap()
.current_frame_holder .current_frame_holder
.as_mut() { .as_mut() {
holder.lock(); holder.lock();
sender.send(holder.get()).unwrap(); sender.send(holder.get()).unwrap();
}; };
}, },
GLPlayerMsgForward::Unlock() => { GLPlayerMsgForward::Unlock() => {
if let Some(holder) = video_renderer if let Some(holder) = video_renderer
.lock() .lock()
.unwrap() .unwrap()
.current_frame_holder .current_frame_holder
.as_mut() { holder.unlock() } .as_mut() { holder.unlock() }
}, },
_ => (), _ => (),
} }
}), })) {
&canceller,
) {
warn!("Could not queue GL player message handler task {:?}", err); warn!("Could not queue GL player message handler task {:?}", err);
} }
}), }),
@ -1513,10 +1504,9 @@ impl HTMLMediaElement {
// the HTMLMediaElementMethods::Ended method // the HTMLMediaElementMethods::Ended method
// Step 3. // Step 3.
let window = self.owner_window();
let this = Trusted::new(self); let this = Trusted::new(self);
let _ = window.task_manager().media_element_task_source().queue( let _ = self.owner_window().task_manager().media_element_task_source().queue(
task!(reaches_the_end_steps: move || { task!(reaches_the_end_steps: move || {
let this = this.root(); let this = this.root();
// Step 3.1. // Step 3.1.
@ -1537,8 +1527,7 @@ impl HTMLMediaElement {
// Step 3.3. // Step 3.3.
this.upcast::<EventTarget>().fire_event(atom!("ended"), CanGc::note()); this.upcast::<EventTarget>().fire_event(atom!("ended"), CanGc::note());
}), })
window.upcast(),
); );
// https://html.spec.whatwg.org/multipage/#dom-media-have_current_data // https://html.spec.whatwg.org/multipage/#dom-media-have_current_data
@ -1548,12 +1537,10 @@ impl HTMLMediaElement {
PlaybackDirection::Backwards => { PlaybackDirection::Backwards => {
if self.playback_position.get() <= self.earliest_possible_position() { if self.playback_position.get() <= self.earliest_possible_position() {
let window = self.owner_window(); self.owner_window()
window
.task_manager() .task_manager()
.media_element_task_source() .media_element_task_source()
.queue_simple_event(self.upcast(), atom!("ended"), &window); .queue_simple_event(self.upcast(), atom!("ended"));
} }
}, },
} }
@ -1737,9 +1724,10 @@ impl HTMLMediaElement {
self.duration.set(f64::INFINITY); self.duration.set(f64::INFINITY);
} }
if previous_duration != self.duration.get() { if previous_duration != self.duration.get() {
let window = self.owner_window(); self.owner_window()
let task_source = window.task_manager().media_element_task_source(); .task_manager()
task_source.queue_simple_event(self.upcast(), atom!("durationchange"), &window); .media_element_task_source()
.queue_simple_event(self.upcast(), atom!("durationchange"));
} }
// Step 5. // Step 5.
@ -2130,11 +2118,10 @@ impl HTMLMediaElementMethods<crate::DomTypeHolder> for HTMLMediaElement {
} }
self.muted.set(value); self.muted.set(value);
let window = self.owner_window(); self.owner_window()
window
.task_manager() .task_manager()
.media_element_task_source() .media_element_task_source()
.queue_simple_event(self.upcast(), atom!("volumechange"), &window); .queue_simple_event(self.upcast(), atom!("volumechange"));
if !self.is_allowed_to_play() { if !self.is_allowed_to_play() {
self.internal_pause_steps(); self.internal_pause_steps();
} }
@ -2229,9 +2216,10 @@ impl HTMLMediaElementMethods<crate::DomTypeHolder> for HTMLMediaElement {
let state = self.ready_state.get(); let state = self.ready_state.get();
let window = self.owner_window(); let task_source = self
// FIXME(nox): Why are errors silenced here? .owner_window()
let task_source = window.task_manager().media_element_task_source(); .task_manager()
.media_element_task_source();
if self.Paused() { if self.Paused() {
// Step 6.1. // Step 6.1.
self.paused.set(false); self.paused.set(false);
@ -2243,14 +2231,14 @@ impl HTMLMediaElementMethods<crate::DomTypeHolder> for HTMLMediaElement {
} }
// Step 6.3. // Step 6.3.
task_source.queue_simple_event(self.upcast(), atom!("play"), &window); task_source.queue_simple_event(self.upcast(), atom!("play"));
// Step 6.4. // Step 6.4.
match state { match state {
ReadyState::HaveNothing | ReadyState::HaveNothing |
ReadyState::HaveMetadata | ReadyState::HaveMetadata |
ReadyState::HaveCurrentData => { ReadyState::HaveCurrentData => {
task_source.queue_simple_event(self.upcast(), atom!("waiting"), &window); task_source.queue_simple_event(self.upcast(), atom!("waiting"));
}, },
ReadyState::HaveFutureData | ReadyState::HaveEnoughData => { ReadyState::HaveFutureData | ReadyState::HaveEnoughData => {
self.notify_about_playing(); self.notify_about_playing();
@ -2262,19 +2250,16 @@ impl HTMLMediaElementMethods<crate::DomTypeHolder> for HTMLMediaElement {
let this = Trusted::new(self); let this = Trusted::new(self);
let generation_id = self.generation_id.get(); let generation_id = self.generation_id.get();
task_source task_source
.queue( .queue(task!(resolve_pending_play_promises: move || {
task!(resolve_pending_play_promises: move || { let this = this.root();
let this = this.root(); if generation_id != this.generation_id.get() {
if generation_id != this.generation_id.get() { return;
return; }
}
this.fulfill_in_flight_play_promises(|| { this.fulfill_in_flight_play_promises(|| {
this.play_media(); this.play_media();
}); });
}), }))
window.upcast(),
)
.unwrap(); .unwrap();
} }
@ -2478,11 +2463,10 @@ impl HTMLMediaElementMethods<crate::DomTypeHolder> for HTMLMediaElement {
if *value != self.volume.get() { if *value != self.volume.get() {
self.volume.set(*value); self.volume.set(*value);
let window = self.owner_window(); self.owner_window()
window
.task_manager() .task_manager()
.media_element_task_source() .media_element_task_source()
.queue_simple_event(self.upcast(), atom!("volumechange"), &window); .queue_simple_event(self.upcast(), atom!("volumechange"));
if !self.is_allowed_to_play() { if !self.is_allowed_to_play() {
self.internal_pause_steps(); self.internal_pause_steps();
} }
@ -2809,11 +2793,10 @@ impl FetchResponseListener for HTMLMediaElementFetchListener {
// https://html.spec.whatwg.org/multipage/#concept-media-load-resource step 4, // https://html.spec.whatwg.org/multipage/#concept-media-load-resource step 4,
// => "If mode is remote" step 2 // => "If mode is remote" step 2
if Instant::now() > self.next_progress_event { if Instant::now() > self.next_progress_event {
let window = elem.owner_window(); elem.owner_window()
window
.task_manager() .task_manager()
.media_element_task_source() .media_element_task_source()
.queue_simple_event(elem.upcast(), atom!("progress"), &window); .queue_simple_event(elem.upcast(), atom!("progress"));
self.next_progress_event = Instant::now() + Duration::from_millis(350); self.next_progress_event = Instant::now() + Duration::from_millis(350);
} }
} }

View file

@ -64,7 +64,6 @@ 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::script_runtime::CanGc;
use crate::task::TaskCanceller;
use crate::task_source::{TaskSource, TaskSourceName}; use crate::task_source::{TaskSource, TaskSourceName};
use crate::unminify::{unminify_js, ScriptSource}; use crate::unminify::{unminify_js, ScriptSource};
@ -102,7 +101,6 @@ impl ScriptSource for ScriptOrigin {
final_url: ServoUrl, final_url: ServoUrl,
url: ServoUrl, url: ServoUrl,
task_source: TaskSource, task_source: TaskSource,
canceller: TaskCanceller,
script_text: String, script_text: String,
fetch_options: ScriptFetchOptions, fetch_options: ScriptFetchOptions,
} }
@ -123,7 +121,7 @@ unsafe extern "C" fn off_thread_compilation_callback(
let fetch_options = context.fetch_options.clone(); let fetch_options = context.fetch_options.clone();
// Continue with <https://html.spec.whatwg.org/multipage/#fetch-a-classic-script> // Continue with <https://html.spec.whatwg.org/multipage/#fetch-a-classic-script>
let _ = context.task_source.queue_with_canceller( let _ = context.task_source.queue(
task!(off_thread_compile_continue: move || { task!(off_thread_compile_continue: move || {
let elem = script_element.root(); let elem = script_element.root();
let global = elem.global(); let global = elem.global();
@ -157,8 +155,7 @@ unsafe extern "C" fn off_thread_compilation_callback(
}; };
finish_fetching_a_classic_script(&elem, script_kind, url, load); finish_fetching_a_classic_script(&elem, script_kind, url, load);
}), })
&context.canceller,
); );
}*/ }*/
@ -476,7 +473,6 @@ impl FetchResponseListener for ClassicContext {
final_url, final_url,
url: self.url.clone(), url: self.url.clone(),
task_source: global.task_manager().dom_manipulation_task_source(), task_source: global.task_manager().dom_manipulation_task_source(),
canceller: global.task_canceller(TaskSourceName::DOMManipulation),
script_text: source_string, script_text: source_string,
fetch_options: self.fetch_options.clone(), fetch_options: self.fetch_options.clone(),
}); });
@ -1061,11 +1057,10 @@ impl HTMLScriptElement {
} }
pub fn queue_error_event(&self) { pub fn queue_error_event(&self) {
let window = self.owner_window(); self.owner_window()
window
.task_manager() .task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue_simple_event(self.upcast(), atom!("error"), &window); .queue_simple_event(self.upcast(), atom!("error"));
} }
pub fn dispatch_load_event(&self, can_gc: CanGc) { pub fn dispatch_load_event(&self, can_gc: CanGc) {

View file

@ -133,11 +133,10 @@ impl HTMLStyleElement {
// No subresource loads were triggered, queue load event // No subresource loads were triggered, queue load event
if self.pending_loads.get() == 0 { if self.pending_loads.get() == 0 {
let window = self.owner_window(); self.owner_window()
window
.task_manager() .task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue_simple_event(self.upcast(), atom!("load"), &window); .queue_simple_event(self.upcast(), atom!("load"));
} }
self.set_stylesheet(sheet); self.set_stylesheet(sheet);

View file

@ -650,8 +650,7 @@ impl VirtualMethods for HTMLTextAreaElement {
} }
} else if event.type_() == atom!("keypress") && !event.DefaultPrevented() { } else if event.type_() == atom!("keypress") && !event.DefaultPrevented() {
if event.IsTrusted() { if event.IsTrusted() {
let window = self.owner_window(); self.owner_window()
window
.task_manager() .task_manager()
.user_interaction_task_source() .user_interaction_task_source()
.queue_event( .queue_event(
@ -659,7 +658,6 @@ impl VirtualMethods for HTMLTextAreaElement {
atom!("input"), atom!("input"),
EventBubbles::Bubbles, EventBubbles::Bubbles,
EventCancelable::NotCancelable, EventCancelable::NotCancelable,
&window,
); );
} }
} else if event.type_() == atom!("compositionstart") || } else if event.type_() == atom!("compositionstart") ||

View file

@ -125,9 +125,10 @@ impl HTMLVideoElement {
let sent_resize = if self.htmlmediaelement.get_ready_state() == ReadyState::HaveNothing { let sent_resize = if self.htmlmediaelement.get_ready_state() == ReadyState::HaveNothing {
None None
} else { } else {
let window = self.owner_window(); self.owner_window()
let task_source = window.task_manager().media_element_task_source(); .task_manager()
task_source.queue_simple_event(self.upcast(), atom!("resize"), &window); .media_element_task_source()
.queue_simple_event(self.upcast(), atom!("resize"));
Some((width, height)) Some((width, height))
}; };

View file

@ -170,16 +170,12 @@ impl OfflineAudioContextMethods<crate::DomTypeHolder> for OfflineAudioContext {
})); }));
let this = Trusted::new(self); let this = Trusted::new(self);
let global = self.global(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let window = global.as_window();
let (task_source, canceller) = window
.task_manager()
.dom_manipulation_task_source_with_canceller();
Builder::new() Builder::new()
.name("OfflineACResolver".to_owned()) .name("OfflineACResolver".to_owned())
.spawn(move || { .spawn(move || {
let _ = receiver.recv(); let _ = receiver.recv();
let _ = task_source.queue_with_canceller( let _ = task_source.queue(
task!(resolve: move || { task!(resolve: move || {
let this = this.root(); let this = this.root();
let processed_audio = processed_audio.lock().unwrap(); let processed_audio = processed_audio.lock().unwrap();
@ -207,8 +203,7 @@ impl OfflineAudioContextMethods<crate::DomTypeHolder> for OfflineAudioContext {
EventCancelable::NotCancelable, EventCancelable::NotCancelable,
&buffer, CanGc::note()); &buffer, CanGc::note());
event.upcast::<Event>().fire(this.upcast(), CanGc::note()); event.upcast::<Event>().fire(this.upcast(), CanGc::note());
}), })
&canceller,
); );
}) })
.unwrap(); .unwrap();

View file

@ -247,7 +247,7 @@ impl Performance {
let task = task!(notify_performance_observers: move || { let task = task!(notify_performance_observers: move || {
owner.root().notify_observers(); owner.root().notify_observers();
}); });
let _ = task_source.queue(task, global); let _ = task_source.queue(task);
} }
} }
let mut observers = self.observers.borrow_mut(); let mut observers = self.observers.borrow_mut();
@ -334,7 +334,7 @@ impl Performance {
let task = task!(notify_performance_observers: move || { let task = task!(notify_performance_observers: move || {
owner.root().notify_observers(); owner.root().notify_observers();
}); });
let _ = task_source.queue(task, global); let _ = task_source.queue(task);
Some(entry_last_index) Some(entry_last_index)
} }

View file

@ -52,7 +52,6 @@ use crate::dom::rtctrackevent::RTCTrackEvent;
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; use crate::script_runtime::CanGc;
use crate::task::TaskCanceller;
use crate::task_source::TaskSource; use crate::task_source::TaskSource;
#[dom_struct] #[dom_struct]
@ -81,75 +80,64 @@ pub struct RTCPeerConnection {
struct RTCSignaller { struct RTCSignaller {
trusted: Trusted<RTCPeerConnection>, trusted: Trusted<RTCPeerConnection>,
task_source: TaskSource, task_source: TaskSource,
canceller: TaskCanceller,
} }
impl WebRtcSignaller for RTCSignaller { impl WebRtcSignaller for RTCSignaller {
fn on_ice_candidate(&self, _: &WebRtcController, candidate: IceCandidate) { fn on_ice_candidate(&self, _: &WebRtcController, candidate: IceCandidate) {
let this = self.trusted.clone(); let this = self.trusted.clone();
let _ = self.task_source.queue_with_canceller( let _ = self.task_source.queue(task!(on_ice_candidate: move || {
task!(on_ice_candidate: move || { let this = this.root();
let this = this.root(); this.on_ice_candidate(candidate, CanGc::note());
this.on_ice_candidate(candidate, CanGc::note()); }));
}),
&self.canceller,
);
} }
fn on_negotiation_needed(&self, _: &WebRtcController) { fn on_negotiation_needed(&self, _: &WebRtcController) {
let this = self.trusted.clone(); let this = self.trusted.clone();
let _ = self.task_source.queue_with_canceller( let _ = self
task!(on_negotiation_needed: move || { .task_source
.queue(task!(on_negotiation_needed: move || {
let this = this.root(); let this = this.root();
this.on_negotiation_needed(CanGc::note()); this.on_negotiation_needed(CanGc::note());
}), }));
&self.canceller,
);
} }
fn update_gathering_state(&self, state: GatheringState) { fn update_gathering_state(&self, state: GatheringState) {
let this = self.trusted.clone(); let this = self.trusted.clone();
let _ = self.task_source.queue_with_canceller( let _ = self
task!(update_gathering_state: move || { .task_source
.queue(task!(update_gathering_state: move || {
let this = this.root(); let this = this.root();
this.update_gathering_state(state, CanGc::note()); this.update_gathering_state(state, CanGc::note());
}), }));
&self.canceller,
);
} }
fn update_ice_connection_state(&self, state: IceConnectionState) { fn update_ice_connection_state(&self, state: IceConnectionState) {
let this = self.trusted.clone(); let this = self.trusted.clone();
let _ = self.task_source.queue_with_canceller( let _ = self
task!(update_ice_connection_state: move || { .task_source
.queue(task!(update_ice_connection_state: move || {
let this = this.root(); let this = this.root();
this.update_ice_connection_state(state, CanGc::note()); this.update_ice_connection_state(state, CanGc::note());
}), }));
&self.canceller,
);
} }
fn update_signaling_state(&self, state: SignalingState) { fn update_signaling_state(&self, state: SignalingState) {
let this = self.trusted.clone(); let this = self.trusted.clone();
let _ = self.task_source.queue_with_canceller( let _ = self
task!(update_signaling_state: move || { .task_source
.queue(task!(update_signaling_state: move || {
let this = this.root(); let this = this.root();
this.update_signaling_state(state, CanGc::note()); this.update_signaling_state(state, CanGc::note());
}), }));
&self.canceller,
);
} }
fn on_add_stream(&self, id: &MediaStreamId, ty: MediaStreamType) { fn on_add_stream(&self, id: &MediaStreamId, ty: MediaStreamType) {
let this = self.trusted.clone(); let this = self.trusted.clone();
let id = *id; let id = *id;
let _ = self.task_source.queue_with_canceller( let _ = self.task_source.queue(task!(on_add_stream: move || {
task!(on_add_stream: move || { let this = this.root();
let this = this.root(); this.on_add_stream(id, ty, CanGc::note());
this.on_add_stream(id, ty, CanGc::note()); }));
}),
&self.canceller,
);
} }
fn on_data_channel_event( fn on_data_channel_event(
@ -160,15 +148,14 @@ impl WebRtcSignaller for RTCSignaller {
) { ) {
// XXX(ferjm) get label and options from channel properties. // XXX(ferjm) get label and options from channel properties.
let this = self.trusted.clone(); let this = self.trusted.clone();
let _ = self.task_source.queue_with_canceller( let _ = self
task!(on_data_channel_event: move || { .task_source
.queue(task!(on_data_channel_event: move || {
let this = this.root(); let this = this.root();
let global = this.global(); let global = this.global();
let _ac = enter_realm(&*global); let _ac = enter_realm(&*global);
this.on_data_channel_event(channel, event, CanGc::note()); this.on_data_channel_event(channel, event, CanGc::note());
}), }));
&self.canceller,
);
} }
fn close(&self) { fn close(&self) {
@ -237,15 +224,10 @@ impl RTCPeerConnection {
fn make_signaller(&self) -> Box<dyn WebRtcSignaller> { fn make_signaller(&self) -> Box<dyn WebRtcSignaller> {
let trusted = Trusted::new(self); let trusted = Trusted::new(self);
let (task_source, canceller) = self let task_source = self.global().task_manager().networking_task_source();
.global()
.as_window()
.task_manager()
.networking_task_source_with_canceller();
Box::new(RTCSignaller { Box::new(RTCSignaller {
trusted, trusted,
task_source, task_source,
canceller,
}) })
} }
@ -460,65 +442,51 @@ impl RTCPeerConnection {
fn create_offer(&self) { fn create_offer(&self) {
let generation = self.offer_answer_generation.get(); let generation = self.offer_answer_generation.get();
let (task_source, canceller) = self let task_source = self.global().task_manager().networking_task_source();
.global()
.as_window()
.task_manager()
.networking_task_source_with_canceller();
let this = Trusted::new(self); let this = Trusted::new(self);
self.controller self.controller
.borrow_mut() .borrow_mut()
.as_ref() .as_ref()
.unwrap() .unwrap()
.create_offer(Box::new(move |desc: SessionDescription| { .create_offer(Box::new(move |desc: SessionDescription| {
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(offer_created: move || {
task!(offer_created: move || { let this = this.root();
let this = this.root(); if this.offer_answer_generation.get() != generation {
if this.offer_answer_generation.get() != generation { // the state has changed since we last created the offer,
// the state has changed since we last created the offer, // create a fresh one
// create a fresh one this.create_offer();
this.create_offer(); } else {
} else { let init: RTCSessionDescriptionInit = desc.convert();
let init: RTCSessionDescriptionInit = desc.convert(); for promise in this.offer_promises.borrow_mut().drain(..) {
for promise in this.offer_promises.borrow_mut().drain(..) { promise.resolve_native(&init);
promise.resolve_native(&init);
}
} }
}), }
&canceller, }));
);
})); }));
} }
fn create_answer(&self) { fn create_answer(&self) {
let generation = self.offer_answer_generation.get(); let generation = self.offer_answer_generation.get();
let (task_source, canceller) = self let task_source = self.global().task_manager().networking_task_source();
.global()
.as_window()
.task_manager()
.networking_task_source_with_canceller();
let this = Trusted::new(self); let this = Trusted::new(self);
self.controller self.controller
.borrow_mut() .borrow_mut()
.as_ref() .as_ref()
.unwrap() .unwrap()
.create_answer(Box::new(move |desc: SessionDescription| { .create_answer(Box::new(move |desc: SessionDescription| {
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(answer_created: move || {
task!(answer_created: move || { let this = this.root();
let this = this.root(); if this.offer_answer_generation.get() != generation {
if this.offer_answer_generation.get() != generation { // the state has changed since we last created the offer,
// the state has changed since we last created the offer, // create a fresh one
// create a fresh one this.create_answer();
this.create_answer(); } else {
} else { let init: RTCSessionDescriptionInit = desc.convert();
let init: RTCSessionDescriptionInit = desc.convert(); for promise in this.answer_promises.borrow_mut().drain(..) {
for promise in this.answer_promises.borrow_mut().drain(..) { promise.resolve_native(&init);
promise.resolve_native(&init);
}
} }
}), }
&canceller, }));
);
})); }));
} }
} }
@ -667,11 +635,7 @@ impl RTCPeerConnectionMethods<crate::DomTypeHolder> for RTCPeerConnection {
let this = Trusted::new(self); let this = Trusted::new(self);
let desc: SessionDescription = desc.convert(); let desc: SessionDescription = desc.convert();
let trusted_promise = TrustedPromise::new(p.clone()); let trusted_promise = TrustedPromise::new(p.clone());
let (task_source, canceller) = self let task_source = self.global().task_manager().networking_task_source();
.global()
.as_window()
.task_manager()
.networking_task_source_with_canceller();
self.controller self.controller
.borrow_mut() .borrow_mut()
.as_ref() .as_ref()
@ -679,23 +643,20 @@ impl RTCPeerConnectionMethods<crate::DomTypeHolder> for RTCPeerConnection {
.set_local_description( .set_local_description(
desc.clone(), desc.clone(),
Box::new(move || { Box::new(move || {
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(local_description_set: move || {
task!(local_description_set: move || { // XXXManishearth spec actually asks for an intricate
// XXXManishearth spec actually asks for an intricate // dance between pending/current local/remote descriptions
// dance between pending/current local/remote descriptions let this = this.root();
let this = this.root(); let desc = desc.convert();
let desc = desc.convert(); let desc = RTCSessionDescription::Constructor(
let desc = RTCSessionDescription::Constructor( this.global().as_window(),
this.global().as_window(), None,
None, CanGc::note(),
CanGc::note(), &desc,
&desc, ).unwrap();
).unwrap(); this.local_description.set(Some(&desc));
this.local_description.set(Some(&desc)); trusted_promise.root().resolve_native(&())
trusted_promise.root().resolve_native(&()) }));
}),
&canceller,
);
}), }),
); );
p p
@ -713,11 +674,7 @@ impl RTCPeerConnectionMethods<crate::DomTypeHolder> for RTCPeerConnection {
let this = Trusted::new(self); let this = Trusted::new(self);
let desc: SessionDescription = desc.convert(); let desc: SessionDescription = desc.convert();
let trusted_promise = TrustedPromise::new(p.clone()); let trusted_promise = TrustedPromise::new(p.clone());
let (task_source, canceller) = self let task_source = self.global().task_manager().networking_task_source();
.global()
.as_window()
.task_manager()
.networking_task_source_with_canceller();
self.controller self.controller
.borrow_mut() .borrow_mut()
.as_ref() .as_ref()
@ -725,23 +682,20 @@ impl RTCPeerConnectionMethods<crate::DomTypeHolder> for RTCPeerConnection {
.set_remote_description( .set_remote_description(
desc.clone(), desc.clone(),
Box::new(move || { Box::new(move || {
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(remote_description_set: move || {
task!(remote_description_set: move || { // XXXManishearth spec actually asks for an intricate
// XXXManishearth spec actually asks for an intricate // dance between pending/current local/remote descriptions
// dance between pending/current local/remote descriptions let this = this.root();
let this = this.root(); let desc = desc.convert();
let desc = desc.convert(); let desc = RTCSessionDescription::Constructor(
let desc = RTCSessionDescription::Constructor( this.global().as_window(),
this.global().as_window(), None,
None, CanGc::note(),
CanGc::note(), &desc,
&desc, ).unwrap();
).unwrap(); this.remote_description.set(Some(&desc));
this.remote_description.set(Some(&desc)); trusted_promise.root().resolve_native(&())
trusted_promise.root().resolve_native(&()) }));
}),
&canceller,
);
}), }),
); );
p p

View file

@ -88,8 +88,8 @@ impl Selection {
return; return;
} }
let this = Trusted::new(self); let this = Trusted::new(self);
let window = self.document.window(); self.document
window .window()
.task_manager() .task_manager()
.user_interaction_task_source() // w3c/selection-api#117 .user_interaction_task_source() // w3c/selection-api#117
.queue( .queue(
@ -97,8 +97,7 @@ impl Selection {
let this = this.root(); let this = this.root();
this.task_queued.set(false); this.task_queued.set(false);
this.document.upcast::<EventTarget>().fire_event(atom!("selectionchange"), CanGc::note()); this.document.upcast::<EventTarget>().fire_event(atom!("selectionchange"), CanGc::note());
}), })
window.upcast(),
) )
.expect("Couldn't queue selectionchange task!"); .expect("Couldn't queue selectionchange task!");
self.task_queued.set(true); self.task_queued.set(true);

View file

@ -26,8 +26,7 @@ use crate::dom::serviceworker::ServiceWorker;
use crate::dom::serviceworkerregistration::ServiceWorkerRegistration; use crate::dom::serviceworkerregistration::ServiceWorkerRegistration;
use crate::realms::{enter_realm, InRealm}; use crate::realms::{enter_realm, InRealm};
use crate::script_runtime::CanGc; use crate::script_runtime::CanGc;
use crate::task::TaskCanceller; use crate::task_source::TaskSource;
use crate::task_source::{TaskSource, TaskSourceName};
#[dom_struct] #[dom_struct]
pub struct ServiceWorkerContainer { pub struct ServiceWorkerContainer {
@ -141,15 +140,10 @@ impl ServiceWorkerContainerMethods<crate::DomTypeHolder> for ServiceWorkerContai
// Setup the callback for reject/resolve of the promise, // Setup the callback for reject/resolve of the promise,
// from steps running "in-parallel" from here in the serviceworker manager. // from steps running "in-parallel" from here in the serviceworker manager.
let (task_source, task_canceller) = ( let task_source = global.task_manager().dom_manipulation_task_source();
global.task_manager().dom_manipulation_task_source(),
global.task_canceller(TaskSourceName::DOMManipulation),
);
let mut handler = RegisterJobResultHandler { let mut handler = RegisterJobResultHandler {
trusted_promise: Some(TrustedPromise::new(promise.clone())), trusted_promise: Some(TrustedPromise::new(promise.clone())),
task_source, task_source,
task_canceller,
}; };
let (job_result_sender, job_result_receiver) = ipc::channel().expect("ipc channel failure"); let (job_result_sender, job_result_receiver) = ipc::channel().expect("ipc channel failure");
@ -190,7 +184,6 @@ impl ServiceWorkerContainerMethods<crate::DomTypeHolder> for ServiceWorkerContai
struct RegisterJobResultHandler { struct RegisterJobResultHandler {
trusted_promise: Option<TrustedPromise>, trusted_promise: Option<TrustedPromise>,
task_source: TaskSource, task_source: TaskSource,
task_canceller: TaskCanceller,
} }
impl RegisterJobResultHandler { impl RegisterJobResultHandler {
@ -206,7 +199,7 @@ impl RegisterJobResultHandler {
.expect("No promise to resolve for SW Register job."); .expect("No promise to resolve for SW Register job.");
// Step 1 // Step 1
let _ = self.task_source.queue_with_canceller( let _ = self.task_source.queue(
task!(reject_promise_with_security_error: move || { task!(reject_promise_with_security_error: move || {
let promise = promise.root(); let promise = promise.root();
let _ac = enter_realm(&*promise.global()); let _ac = enter_realm(&*promise.global());
@ -219,8 +212,7 @@ impl RegisterJobResultHandler {
}, },
} }
}), })
&self.task_canceller,
); );
// TODO: step 2, handle equivalent jobs. // TODO: step 2, handle equivalent jobs.
@ -232,35 +224,32 @@ impl RegisterJobResultHandler {
.expect("No promise to resolve for SW Register job."); .expect("No promise to resolve for SW Register job.");
// Step 1 // Step 1
let _ = self.task_source.queue_with_canceller( let _ = self.task_source.queue(task!(resolve_promise: move || {
task!(resolve_promise: move || { let promise = promise.root();
let promise = promise.root(); let global = promise.global();
let global = promise.global(); let _ac = enter_realm(&*global);
let _ac = enter_realm(&*global);
// Step 1.1 // Step 1.1
let JobResultValue::Registration { let JobResultValue::Registration {
id, id,
installing_worker, installing_worker,
waiting_worker, waiting_worker,
active_worker, active_worker,
} = value; } = value;
// Step 1.2 (Job type is "register"). // Step 1.2 (Job type is "register").
let registration = global.get_serviceworker_registration( let registration = global.get_serviceworker_registration(
&job.script_url, &job.script_url,
&job.scope_url, &job.scope_url,
id, id,
installing_worker, installing_worker,
waiting_worker, waiting_worker,
active_worker, active_worker,
); );
// Step 1.4 // Step 1.4
promise.resolve_native(&*registration); promise.resolve_native(&*registration);
}), }));
&self.task_canceller,
);
// TODO: step 2, handle equivalent jobs. // TODO: step 2, handle equivalent jobs.
}, },

View file

@ -412,7 +412,7 @@ impl ServiceWorkerGlobalScope {
} }
}, },
reporter_name, reporter_name,
scope.script_chan(), global.event_loop_sender(),
CommonScriptMsg::CollectReports, CommonScriptMsg::CollectReports,
); );
@ -485,7 +485,7 @@ impl ServiceWorkerGlobalScope {
} }
} }
pub fn script_chan(&self) -> Box<dyn ScriptChan + Send> { pub(crate) fn event_loop_sender(&self) -> Box<dyn ScriptChan + Send> {
Box::new(ServiceWorkerChan { Box::new(ServiceWorkerChan {
sender: self.own_sender.clone(), sender: self.own_sender.clone(),
}) })

View file

@ -209,29 +209,25 @@ impl Storage {
let global = self.global(); let global = self.global();
let this = Trusted::new(self); let this = Trusted::new(self);
global global
.as_window()
.task_manager() .task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue( .queue(task!(send_storage_notification: move || {
task!(send_storage_notification: move || { let this = this.root();
let this = this.root(); let global = this.global();
let global = this.global(); let event = StorageEvent::new(
let event = StorageEvent::new( global.as_window(),
global.as_window(), atom!("storage"),
atom!("storage"), EventBubbles::DoesNotBubble,
EventBubbles::DoesNotBubble, EventCancelable::NotCancelable,
EventCancelable::NotCancelable, key.map(DOMString::from),
key.map(DOMString::from), old_value.map(DOMString::from),
old_value.map(DOMString::from), new_value.map(DOMString::from),
new_value.map(DOMString::from), DOMString::from(url.into_string()),
DOMString::from(url.into_string()), Some(&this),
Some(&this), CanGc::note()
CanGc::note() );
); event.upcast::<Event>().fire(global.upcast(), CanGc::note());
event.upcast::<Event>().fire(global.upcast(), CanGc::note()); }))
}),
global.upcast(),
)
.unwrap(); .unwrap();
} }
} }

View file

@ -40,7 +40,6 @@ use crate::dom::bindings::codegen::UnionTypes::{
}; };
use crate::dom::bindings::error::{Error, Fallible}; use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::import::module::SafeJSContext; use crate::dom::bindings::import::module::SafeJSContext;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::DomRoot;
@ -49,12 +48,8 @@ use crate::dom::bindings::trace::RootedTraceableBox;
use crate::dom::cryptokey::{CryptoKey, Handle}; use crate::dom::cryptokey::{CryptoKey, Handle};
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise; use crate::dom::promise::Promise;
use crate::dom::window::Window;
use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::realms::InRealm; use crate::realms::InRealm;
use crate::script_runtime::{CanGc, JSContext}; use crate::script_runtime::{CanGc, JSContext};
use crate::task::TaskCanceller;
use crate::task_source::TaskSource;
// String constants for algorithms/curves // String constants for algorithms/curves
const ALG_AES_CBC: &str = "AES-CBC"; const ALG_AES_CBC: &str = "AES-CBC";
@ -140,20 +135,6 @@ impl SubtleCrypto {
CanGc::note(), CanGc::note(),
) )
} }
fn task_source_with_canceller(&self) -> (TaskSource, TaskCanceller) {
if let Some(window) = self.global().downcast::<Window>() {
window
.task_manager()
.dom_manipulation_task_source_with_canceller()
} else if let Some(worker_global) = self.global().downcast::<WorkerGlobalScope>() {
let task_source = worker_global.task_manager().dom_manipulation_task_source();
let canceller = worker_global.task_canceller();
(task_source, canceller)
} else {
unreachable!("Couldn't downcast to Window or WorkerGlobalScope!");
}
}
} }
impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto { impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
@ -181,13 +162,13 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(), ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
}; };
let (task_source, canceller) = self.task_source_with_canceller(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let this = Trusted::new(self); let this = Trusted::new(self);
let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_promise = TrustedPromise::new(promise.clone());
let trusted_key = Trusted::new(key); let trusted_key = Trusted::new(key);
let key_alg = key.algorithm(); let key_alg = key.algorithm();
let valid_usage = key.usages().contains(&KeyUsage::Encrypt); let valid_usage = key.usages().contains(&KeyUsage::Encrypt);
let _ = task_source.queue_with_canceller( let _ = task_source.queue(
task!(encrypt: move || { task!(encrypt: move || {
let subtle = this.root(); let subtle = this.root();
let promise = trusted_promise.root(); let promise = trusted_promise.root();
@ -206,8 +187,7 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
return; return;
} }
promise.resolve_native(&*array_buffer_ptr.handle()); promise.resolve_native(&*array_buffer_ptr.handle());
}), })
&canceller,
); );
promise promise
@ -237,13 +217,13 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(), ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
}; };
let (task_source, canceller) = self.task_source_with_canceller(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let this = Trusted::new(self); let this = Trusted::new(self);
let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_promise = TrustedPromise::new(promise.clone());
let trusted_key = Trusted::new(key); let trusted_key = Trusted::new(key);
let key_alg = key.algorithm(); let key_alg = key.algorithm();
let valid_usage = key.usages().contains(&KeyUsage::Decrypt); let valid_usage = key.usages().contains(&KeyUsage::Decrypt);
let _ = task_source.queue_with_canceller( let _ = task_source.queue(
task!(decrypt: move || { task!(decrypt: move || {
let subtle = this.root(); let subtle = this.root();
let promise = trusted_promise.root(); let promise = trusted_promise.root();
@ -262,8 +242,7 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
} }
promise.resolve_native(&*array_buffer_ptr.handle()); promise.resolve_native(&*array_buffer_ptr.handle());
}), })
&canceller,
); );
promise promise
@ -304,51 +283,48 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
// NOTE: We did that in preparation of Step 4. // NOTE: We did that in preparation of Step 4.
// Step 6. Return promise and perform the remaining steps in parallel. // Step 6. Return promise and perform the remaining steps in parallel.
let (task_source, canceller) = self.task_source_with_canceller(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_promise = TrustedPromise::new(promise.clone());
let trusted_key = Trusted::new(key); let trusted_key = Trusted::new(key);
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(sign: move || {
task!(sign: move || { // Step 7. If the following steps or referenced procedures say to throw an error, reject promise
// Step 7. If the following steps or referenced procedures say to throw an error, reject promise // with the returned error and then terminate the algorithm.
// with the returned error and then terminate the algorithm. let promise = trusted_promise.root();
let promise = trusted_promise.root(); let key = trusted_key.root();
let key = trusted_key.root();
// Step 8. If the name member of normalizedAlgorithm is not equal to the name attribute of the // Step 8. If the name member of normalizedAlgorithm is not equal to the name attribute of the
// [[algorithm]] internal slot of key then throw an InvalidAccessError. // [[algorithm]] internal slot of key then throw an InvalidAccessError.
if normalized_algorithm.name() != key.algorithm() { if normalized_algorithm.name() != key.algorithm() {
promise.reject_error(Error::InvalidAccess); promise.reject_error(Error::InvalidAccess);
return;
}
// Step 9. If the [[usages]] internal slot of key does not contain an entry that is "sign",
// then throw an InvalidAccessError.
if !key.usages().contains(&KeyUsage::Sign) {
promise.reject_error(Error::InvalidAccess);
return;
}
// Step 10. Let result be the result of performing the sign operation specified by normalizedAlgorithm
// using key and algorithm and with data as message.
let cx = GlobalScope::get_cx();
let result = match normalized_algorithm.sign(cx, &key, &data) {
Ok(signature) => signature,
Err(e) => {
promise.reject_error(e);
return; return;
} }
};
// Step 9. If the [[usages]] internal slot of key does not contain an entry that is "sign", rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
// then throw an InvalidAccessError. create_buffer_source::<ArrayBufferU8>(cx, &result, array_buffer_ptr.handle_mut())
if !key.usages().contains(&KeyUsage::Sign) { .expect("failed to create buffer source for exported key.");
promise.reject_error(Error::InvalidAccess);
return;
}
// Step 10. Let result be the result of performing the sign operation specified by normalizedAlgorithm // Step 9. Resolve promise with result.
// using key and algorithm and with data as message. promise.resolve_native(&*array_buffer_ptr);
let cx = GlobalScope::get_cx(); }));
let result = match normalized_algorithm.sign(cx, &key, &data) {
Ok(signature) => signature,
Err(e) => {
promise.reject_error(e);
return;
}
};
rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
create_buffer_source::<ArrayBufferU8>(cx, &result, array_buffer_ptr.handle_mut())
.expect("failed to create buffer source for exported key.");
// Step 9. Resolve promise with result.
promise.resolve_native(&*array_buffer_ptr);
}),
&canceller,
);
promise promise
} }
@ -397,47 +373,44 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
// NOTE: We did that in preparation of Step 6. // NOTE: We did that in preparation of Step 6.
// Step 7. Return promise and perform the remaining steps in parallel. // Step 7. Return promise and perform the remaining steps in parallel.
let (task_source, canceller) = self.task_source_with_canceller(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_promise = TrustedPromise::new(promise.clone());
let trusted_key = Trusted::new(key); let trusted_key = Trusted::new(key);
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(sign: move || {
task!(sign: move || { // Step 8. If the following steps or referenced procedures say to throw an error, reject promise
// Step 8. If the following steps or referenced procedures say to throw an error, reject promise // with the returned error and then terminate the algorithm.
// with the returned error and then terminate the algorithm. let promise = trusted_promise.root();
let promise = trusted_promise.root(); let key = trusted_key.root();
let key = trusted_key.root();
// Step 9. If the name member of normalizedAlgorithm is not equal to the name attribute of the // Step 9. If the name member of normalizedAlgorithm is not equal to the name attribute of the
// [[algorithm]] internal slot of key then throw an InvalidAccessError. // [[algorithm]] internal slot of key then throw an InvalidAccessError.
if normalized_algorithm.name() != key.algorithm() { if normalized_algorithm.name() != key.algorithm() {
promise.reject_error(Error::InvalidAccess); promise.reject_error(Error::InvalidAccess);
return;
}
// Step 10. If the [[usages]] internal slot of key does not contain an entry that is "verify",
// then throw an InvalidAccessError.
if !key.usages().contains(&KeyUsage::Verify) {
promise.reject_error(Error::InvalidAccess);
return;
}
// Step 1. Let result be the result of performing the verify operation specified by normalizedAlgorithm
// using key, algorithm and signature and with data as message.
let cx = GlobalScope::get_cx();
let result = match normalized_algorithm.verify(cx, &key, &data, &signature) {
Ok(result) => result,
Err(e) => {
promise.reject_error(e);
return; return;
} }
};
// Step 10. If the [[usages]] internal slot of key does not contain an entry that is "verify", // Step 9. Resolve promise with result.
// then throw an InvalidAccessError. promise.resolve_native(&result);
if !key.usages().contains(&KeyUsage::Verify) { }));
promise.reject_error(Error::InvalidAccess);
return;
}
// Step 1. Let result be the result of performing the verify operation specified by normalizedAlgorithm
// using key, algorithm and signature and with data as message.
let cx = GlobalScope::get_cx();
let result = match normalized_algorithm.verify(cx, &key, &data, &signature) {
Ok(result) => result,
Err(e) => {
promise.reject_error(e);
return;
}
};
// Step 9. Resolve promise with result.
promise.resolve_native(&result);
}),
&canceller,
);
promise promise
} }
@ -476,10 +449,10 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
// NOTE: We did that in preparation of Step 4. // NOTE: We did that in preparation of Step 4.
// Step 6. Return promise and perform the remaining steps in parallel. // Step 6. Return promise and perform the remaining steps in parallel.
let (task_source, canceller) = self.task_source_with_canceller(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_promise = TrustedPromise::new(promise.clone());
let _ = task_source.queue_with_canceller( let _ = task_source.queue(
task!(generate_key: move || { task!(generate_key: move || {
// Step 7. If the following steps or referenced procedures say to throw an error, reject promise // Step 7. If the following steps or referenced procedures say to throw an error, reject promise
// with the returned error and then terminate the algorithm. // with the returned error and then terminate the algorithm.
@ -503,8 +476,7 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
// Step 9. Resolve promise with result. // Step 9. Resolve promise with result.
promise.resolve_native(&*array_buffer_ptr); promise.resolve_native(&*array_buffer_ptr);
}), })
&canceller,
); );
promise promise
@ -529,22 +501,19 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
}, },
}; };
let (task_source, canceller) = self.task_source_with_canceller(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let this = Trusted::new(self); let this = Trusted::new(self);
let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_promise = TrustedPromise::new(promise.clone());
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(generate_key: move || {
task!(generate_key: move || { let subtle = this.root();
let subtle = this.root(); let promise = trusted_promise.root();
let promise = trusted_promise.root(); let key = normalized_algorithm.generate_key(&subtle, key_usages, extractable);
let key = normalized_algorithm.generate_key(&subtle, key_usages, extractable);
match key { match key {
Ok(key) => promise.resolve_native(&key), Ok(key) => promise.resolve_native(&key),
Err(e) => promise.reject_error(e), Err(e) => promise.reject_error(e),
} }
}), }));
&canceller,
);
promise promise
} }
@ -604,11 +573,11 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
// NOTE: We created the promise earlier, after Step 1. // NOTE: We created the promise earlier, after Step 1.
// Step 9. Return promise and perform the remaining steps in parallel. // Step 9. Return promise and perform the remaining steps in parallel.
let (task_source, canceller) = self.task_source_with_canceller(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_promise = TrustedPromise::new(promise.clone());
let trusted_base_key = Trusted::new(base_key); let trusted_base_key = Trusted::new(base_key);
let this = Trusted::new(self); let this = Trusted::new(self);
let _ = task_source.queue_with_canceller( let _ = task_source.queue(
task!(derive_key: move || { task!(derive_key: move || {
// Step 10. If the following steps or referenced procedures say to throw an error, reject promise // Step 10. If the following steps or referenced procedures say to throw an error, reject promise
// with the returned error and then terminate the algorithm. // with the returned error and then terminate the algorithm.
@ -674,7 +643,6 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
// Step 17. Resolve promise with result. // Step 17. Resolve promise with result.
promise.resolve_native(&*result); promise.resolve_native(&*result);
}), }),
&canceller,
); );
promise promise
@ -709,47 +677,44 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
// NOTE: We did that in preparation of Step 3. // NOTE: We did that in preparation of Step 3.
// Step 5. Return promise and perform the remaining steps in parallel. // Step 5. Return promise and perform the remaining steps in parallel.
let (task_source, canceller) = self.task_source_with_canceller(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_promise = TrustedPromise::new(promise.clone());
let trusted_base_key = Trusted::new(base_key); let trusted_base_key = Trusted::new(base_key);
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(import_key: move || {
task!(import_key: move || { // Step 6. If the following steps or referenced procedures say to throw an error,
// Step 6. If the following steps or referenced procedures say to throw an error, // reject promise with the returned error and then terminate the algorithm.
// reject promise with the returned error and then terminate the algorithm.
// TODO Step 7. If the name member of normalizedAlgorithm is not equal to the name attribute // TODO Step 7. If the name member of normalizedAlgorithm is not equal to the name attribute
// of the [[algorithm]] internal slot of baseKey then throw an InvalidAccessError. // of the [[algorithm]] internal slot of baseKey then throw an InvalidAccessError.
let promise = trusted_promise.root(); let promise = trusted_promise.root();
let base_key = trusted_base_key.root(); let base_key = trusted_base_key.root();
// Step 8. If the [[usages]] internal slot of baseKey does not contain an entry that // Step 8. If the [[usages]] internal slot of baseKey does not contain an entry that
// is "deriveBits", then throw an InvalidAccessError. // is "deriveBits", then throw an InvalidAccessError.
if !base_key.usages().contains(&KeyUsage::DeriveBits) { if !base_key.usages().contains(&KeyUsage::DeriveBits) {
promise.reject_error(Error::InvalidAccess); promise.reject_error(Error::InvalidAccess);
return;
}
// Step 9. Let result be the result of creating an ArrayBuffer containing the result of performing the
// derive bits operation specified by normalizedAlgorithm using baseKey, algorithm and length.
let cx = GlobalScope::get_cx();
rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
let result = match normalized_algorithm.derive_bits(&base_key, length) {
Ok(derived_bits) => derived_bits,
Err(e) => {
promise.reject_error(e);
return; return;
} }
};
// Step 9. Let result be the result of creating an ArrayBuffer containing the result of performing the create_buffer_source::<ArrayBufferU8>(cx, &result, array_buffer_ptr.handle_mut())
// derive bits operation specified by normalizedAlgorithm using baseKey, algorithm and length. .expect("failed to create buffer source for derived bits.");
let cx = GlobalScope::get_cx();
rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
let result = match normalized_algorithm.derive_bits(&base_key, length) {
Ok(derived_bits) => derived_bits,
Err(e) => {
promise.reject_error(e);
return;
}
};
create_buffer_source::<ArrayBufferU8>(cx, &result, array_buffer_ptr.handle_mut()) // Step 10. Resolve promise with result.
.expect("failed to create buffer source for derived bits."); promise.resolve_native(&*array_buffer_ptr);
}));
// Step 10. Resolve promise with result.
promise.resolve_native(&*array_buffer_ptr);
}),
&canceller,
);
promise promise
} }
@ -801,10 +766,10 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
}, },
}; };
let (task_source, canceller) = self.task_source_with_canceller(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let this = Trusted::new(self); let this = Trusted::new(self);
let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_promise = TrustedPromise::new(promise.clone());
let _ = task_source.queue_with_canceller( let _ = task_source.queue(
task!(import_key: move || { task!(import_key: move || {
let subtle = this.root(); let subtle = this.root();
let promise = trusted_promise.root(); let promise = trusted_promise.root();
@ -814,7 +779,6 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
Err(e) => promise.reject_error(e), Err(e) => promise.reject_error(e),
}; };
}), }),
&canceller,
); );
promise promise
@ -830,11 +794,11 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
) -> Rc<Promise> { ) -> Rc<Promise> {
let promise = Promise::new_in_current_realm(comp, can_gc); let promise = Promise::new_in_current_realm(comp, can_gc);
let (task_source, canceller) = self.task_source_with_canceller(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let this = Trusted::new(self); let this = Trusted::new(self);
let trusted_key = Trusted::new(key); let trusted_key = Trusted::new(key);
let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_promise = TrustedPromise::new(promise.clone());
let _ = task_source.queue_with_canceller( let _ = task_source.queue(
task!(export_key: move || { task!(export_key: move || {
let subtle = this.root(); let subtle = this.root();
let promise = trusted_promise.root(); let promise = trusted_promise.root();
@ -872,7 +836,6 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
Err(e) => promise.reject_error(e), Err(e) => promise.reject_error(e),
} }
}), }),
&canceller,
); );
promise promise
@ -898,12 +861,12 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
}, },
}; };
let (task_source, canceller) = self.task_source_with_canceller(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let this = Trusted::new(self); let this = Trusted::new(self);
let trusted_key = Trusted::new(key); let trusted_key = Trusted::new(key);
let trusted_wrapping_key = Trusted::new(wrapping_key); let trusted_wrapping_key = Trusted::new(wrapping_key);
let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_promise = TrustedPromise::new(promise.clone());
let _ = task_source.queue_with_canceller( let _ = task_source.queue(
task!(wrap_key: move || { task!(wrap_key: move || {
let subtle = this.root(); let subtle = this.root();
let promise = trusted_promise.root(); let promise = trusted_promise.root();
@ -996,7 +959,6 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
Err(e) => promise.reject_error(e), Err(e) => promise.reject_error(e),
} }
}), }),
&canceller
); );
promise promise
@ -1037,11 +999,11 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
}, },
}; };
let (task_source, canceller) = self.task_source_with_canceller(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let this = Trusted::new(self); let this = Trusted::new(self);
let trusted_key = Trusted::new(unwrapping_key); let trusted_key = Trusted::new(unwrapping_key);
let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_promise = TrustedPromise::new(promise.clone());
let _ = task_source.queue_with_canceller( let _ = task_source.queue(
task!(unwrap_key: move || { task!(unwrap_key: move || {
let subtle = this.root(); let subtle = this.root();
let promise = trusted_promise.root(); let promise = trusted_promise.root();
@ -1103,7 +1065,6 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
Err(e) => promise.reject_error(e), Err(e) => promise.reject_error(e),
} }
}), }),
&canceller
); );
promise promise

View file

@ -300,8 +300,8 @@ impl<'a, E: TextControlElement> TextControlSelection<'a, E> {
// Step 6 // Step 6
if textinput.selection_state() != original_selection_state { if textinput.selection_state() != original_selection_state {
let window = self.element.owner_window(); self.element
window .owner_window()
.task_manager() .task_manager()
.user_interaction_task_source() .user_interaction_task_source()
.queue_event( .queue_event(
@ -309,7 +309,6 @@ impl<'a, E: TextControlElement> TextControlSelection<'a, E> {
atom!("select"), atom!("select"),
EventBubbles::Bubbles, EventBubbles::Bubbles,
EventCancelable::NotCancelable, EventCancelable::NotCancelable,
&window,
); );
} }

View file

@ -63,38 +63,30 @@ impl TextTrackList {
self.dom_tracks.borrow_mut().push(Dom::from_ref(track)); self.dom_tracks.borrow_mut().push(Dom::from_ref(track));
let this = Trusted::new(self); let this = Trusted::new(self);
let (source, canceller) = &self let task_source = self.global().task_manager().media_element_task_source();
.global()
.as_window()
.task_manager()
.media_element_task_source_with_canceller();
let idx = match self.find(track) { let Some(idx) = self.find(track) else {
Some(t) => t, return;
None => return,
}; };
let _ = source.queue_with_canceller( let _ = task_source.queue(task!(track_event_queue: move || {
task!(track_event_queue: move || { let this = this.root();
let this = this.root();
if let Some(track) = this.item(idx) { if let Some(track) = this.item(idx) {
let event = TrackEvent::new( let event = TrackEvent::new(
&this.global(), &this.global(),
atom!("addtrack"), atom!("addtrack"),
false, false,
false, false,
&Some(VideoTrackOrAudioTrackOrTextTrack::TextTrack( &Some(VideoTrackOrAudioTrackOrTextTrack::TextTrack(
DomRoot::from_ref(&track) DomRoot::from_ref(&track)
)), )),
CanGc::note() CanGc::note()
); );
event.upcast::<Event>().fire(this.upcast::<EventTarget>(), CanGc::note()); event.upcast::<Event>().fire(this.upcast::<EventTarget>(), CanGc::note());
} }
}), }));
canceller,
);
track.add_track_list(self); track.add_track_list(self);
} }
} }

View file

@ -81,12 +81,8 @@ impl VideoTrackList {
return; return;
} }
let global = &self.global();
let this = Trusted::new(self); let this = Trusted::new(self);
let (source, canceller) = global let task_source = self.global().task_manager().media_element_task_source();
.as_window()
.task_manager()
.media_element_task_source_with_canceller();
if let Some(current) = self.selected_index() { if let Some(current) = self.selected_index() {
self.tracks.borrow()[current].set_selected(false); self.tracks.borrow()[current].set_selected(false);
@ -97,13 +93,10 @@ impl VideoTrackList {
media_element.set_video_track(idx, value); media_element.set_video_track(idx, value);
} }
let _ = source.queue_with_canceller( let _ = task_source.queue(task!(media_track_change: move || {
task!(media_track_change: move || { let this = this.root();
let this = this.root(); this.upcast::<EventTarget>().fire_event(atom!("change"), CanGc::note());
this.upcast::<EventTarget>().fire_event(atom!("change"), CanGc::note()); }));
}),
&canceller,
);
} }
pub fn add(&self, track: &VideoTrack) { pub fn add(&self, track: &VideoTrack) {

View file

@ -171,12 +171,10 @@ impl WebGLQuery {
this.update_results(&context); this.update_results(&context);
}); });
let global = self.global(); self.global()
global
.as_window()
.task_manager() .task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue(task, global.upcast()) .queue(task)
.unwrap(); .unwrap();
} }

View file

@ -59,7 +59,6 @@ impl WebGLSync {
) -> Option<u32> { ) -> Option<u32> {
match self.client_wait_status.get() { match self.client_wait_status.get() {
Some(constants::TIMEOUT_EXPIRED) | Some(constants::WAIT_FAILED) | None => { Some(constants::TIMEOUT_EXPIRED) | Some(constants::WAIT_FAILED) | None => {
let global = self.global();
let this = Trusted::new(self); let this = Trusted::new(self);
let context = Trusted::new(context); let context = Trusted::new(context);
let task = task!(request_client_wait_status: move || { let task = task!(request_client_wait_status: move || {
@ -74,11 +73,10 @@ impl WebGLSync {
)); ));
this.client_wait_status.set(Some(receiver.recv().unwrap())); this.client_wait_status.set(Some(receiver.recv().unwrap()));
}); });
global self.global()
.as_window()
.task_manager() .task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue(task, global.upcast()) .queue(task)
.unwrap(); .unwrap();
}, },
_ => {}, _ => {},
@ -101,7 +99,6 @@ impl WebGLSync {
pub fn get_sync_status(&self, pname: u32, context: &WebGLRenderingContext) -> Option<u32> { pub fn get_sync_status(&self, pname: u32, context: &WebGLRenderingContext) -> Option<u32> {
match self.sync_status.get() { match self.sync_status.get() {
Some(constants::UNSIGNALED) | None => { Some(constants::UNSIGNALED) | None => {
let global = self.global();
let this = Trusted::new(self); let this = Trusted::new(self);
let context = Trusted::new(context); let context = Trusted::new(context);
let task = task!(request_sync_status: move || { let task = task!(request_sync_status: move || {
@ -111,11 +108,10 @@ impl WebGLSync {
context.send_command(WebGLCommand::GetSyncParameter(this.sync_id, pname, sender)); context.send_command(WebGLCommand::GetSyncParameter(this.sync_id, pname, sender));
this.sync_status.set(Some(receiver.recv().unwrap())); this.sync_status.set(Some(receiver.recv().unwrap()));
}); });
global self.global()
.as_window()
.task_manager() .task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue(task, global.upcast()) .queue(task)
.unwrap(); .unwrap();
}, },
_ => {}, _ => {},

View file

@ -25,7 +25,6 @@ use crate::dom::promise::Promise;
use crate::dom::webgpu::gpuadapter::GPUAdapter; use crate::dom::webgpu::gpuadapter::GPUAdapter;
use crate::realms::InRealm; use crate::realms::InRealm;
use crate::script_runtime::CanGc; use crate::script_runtime::CanGc;
use crate::task_source::TaskSourceName;
#[dom_struct] #[dom_struct]
#[allow(clippy::upper_case_acronyms)] #[allow(clippy::upper_case_acronyms)]
@ -73,9 +72,6 @@ pub fn response_async<T: AsyncWGPUListener + DomObject + 'static>(
.global() .global()
.task_manager() .task_manager()
.dom_manipulation_task_source(); .dom_manipulation_task_source();
let canceller = receiver
.global()
.task_canceller(TaskSourceName::DOMManipulation);
let mut trusted: Option<TrustedPromise> = Some(TrustedPromise::new(promise.clone())); let mut trusted: Option<TrustedPromise> = Some(TrustedPromise::new(promise.clone()));
let trusted_receiver = Trusted::new(receiver); let trusted_receiver = Trusted::new(receiver);
ROUTER.add_typed_route( ROUTER.add_typed_route(
@ -92,12 +88,9 @@ pub fn response_async<T: AsyncWGPUListener + DomObject + 'static>(
trusted, trusted,
receiver: trusted_receiver.clone(), receiver: trusted_receiver.clone(),
}; };
let result = task_source.queue_with_canceller( let result = task_source.queue(task!(process_webgpu_task: move|| {
task!(process_webgpu_task: move|| { context.response(message.unwrap(), CanGc::note());
context.response(message.unwrap(), CanGc::note()); }));
}),
&canceller,
);
if let Err(err) = result { if let Err(err) = result {
error!("Failed to queue GPU listener-task: {:?}", err); error!("Failed to queue GPU listener-task: {:?}", err);
} }

View file

@ -39,8 +39,8 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::messageevent::MessageEvent; use crate::dom::messageevent::MessageEvent;
use crate::script_runtime::CanGc; use crate::script_runtime::CanGc;
use crate::task::{TaskCanceller, TaskOnce}; use crate::task::TaskOnce;
use crate::task_source::{TaskSource, TaskSourceName}; use crate::task_source::TaskSource;
#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)] #[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
enum WebSocketRequestState { enum WebSocketRequestState {
@ -71,7 +71,6 @@ mod close_code {
fn close_the_websocket_connection( fn close_the_websocket_connection(
address: Trusted<WebSocket>, address: Trusted<WebSocket>,
task_source: &TaskSource, task_source: &TaskSource,
canceller: &TaskCanceller,
code: Option<u16>, code: Option<u16>,
reason: String, reason: String,
) { ) {
@ -81,21 +80,17 @@ fn close_the_websocket_connection(
code, code,
reason: Some(reason), reason: Some(reason),
}; };
let _ = task_source.queue_with_canceller(close_task, canceller); let _ = task_source.queue(close_task);
} }
fn fail_the_websocket_connection( fn fail_the_websocket_connection(address: Trusted<WebSocket>, task_source: &TaskSource) {
address: Trusted<WebSocket>,
task_source: &TaskSource,
canceller: &TaskCanceller,
) {
let close_task = CloseTask { let close_task = CloseTask {
address, address,
failed: true, failed: true,
code: Some(close_code::ABNORMAL), code: Some(close_code::ABNORMAL),
reason: None, reason: None,
}; };
let _ = task_source.queue_with_canceller(close_task, canceller); let _ = task_source.queue(close_task);
} }
#[dom_struct] #[dom_struct]
@ -276,7 +271,6 @@ impl WebSocketMethods<crate::DomTypeHolder> for WebSocket {
.send(CoreResourceMsg::Fetch(request, channels)); .send(CoreResourceMsg::Fetch(request, channels));
let task_source = global.task_manager().websocket_task_source(); let task_source = global.task_manager().websocket_task_source();
let canceller = global.task_canceller(TaskSourceName::WebSocket);
ROUTER.add_typed_route( ROUTER.add_typed_route(
dom_event_receiver.to_ipc_receiver(), dom_event_receiver.to_ipc_receiver(),
Box::new(move |message| match message.unwrap() { Box::new(move |message| match message.unwrap() {
@ -285,26 +279,20 @@ impl WebSocketMethods<crate::DomTypeHolder> for WebSocket {
address: address.clone(), address: address.clone(),
protocol_in_use, protocol_in_use,
}; };
let _ = task_source.queue_with_canceller(open_thread, &canceller); let _ = task_source.queue(open_thread);
}, },
WebSocketNetworkEvent::MessageReceived(message) => { WebSocketNetworkEvent::MessageReceived(message) => {
let message_thread = MessageReceivedTask { let message_thread = MessageReceivedTask {
address: address.clone(), address: address.clone(),
message, message,
}; };
let _ = task_source.queue_with_canceller(message_thread, &canceller); let _ = task_source.queue(message_thread);
}, },
WebSocketNetworkEvent::Fail => { WebSocketNetworkEvent::Fail => {
fail_the_websocket_connection(address.clone(), &task_source, &canceller); fail_the_websocket_connection(address.clone(), &task_source);
}, },
WebSocketNetworkEvent::Close(code, reason) => { WebSocketNetworkEvent::Close(code, reason) => {
close_the_websocket_connection( close_the_websocket_connection(address.clone(), &task_source, code, reason);
address.clone(),
&task_source,
&canceller,
code,
reason,
);
}, },
}), }),
); );
@ -439,15 +427,8 @@ impl WebSocketMethods<crate::DomTypeHolder> for WebSocket {
self.ready_state.set(WebSocketRequestState::Closing); self.ready_state.set(WebSocketRequestState::Closing);
let address = Trusted::new(self); let address = Trusted::new(self);
// TODO: use a dedicated task source,
// https://html.spec.whatwg.org/multipage/#websocket-task-source
// When making the switch, also update the task_canceller call.
let task_source = self.global().task_manager().websocket_task_source(); let task_source = self.global().task_manager().websocket_task_source();
fail_the_websocket_connection( fail_the_websocket_connection(address, &task_source);
address,
&task_source,
&self.global().task_canceller(TaskSourceName::WebSocket),
);
}, },
WebSocketRequestState::Open => { WebSocketRequestState::Open => {
self.ready_state.set(WebSocketRequestState::Closing); self.ready_state.set(WebSocketRequestState::Closing);

View file

@ -306,10 +306,7 @@ impl FakeXRDeviceMethods<crate::DomTypeHolder> for FakeXRDevice {
let global = self.global(); let global = self.global();
let p = Promise::new(&global, can_gc); let p = Promise::new(&global, can_gc);
let mut trusted = Some(TrustedPromise::new(p.clone())); let mut trusted = Some(TrustedPromise::new(p.clone()));
let (task_source, canceller) = global let task_source = global.task_manager().dom_manipulation_task_source();
.as_window()
.task_manager()
.dom_manipulation_task_source_with_canceller();
let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap(); let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap();
ROUTER.add_typed_route( ROUTER.add_typed_route(
@ -318,7 +315,7 @@ impl FakeXRDeviceMethods<crate::DomTypeHolder> for FakeXRDevice {
let trusted = trusted let trusted = trusted
.take() .take()
.expect("disconnect callback called multiple times"); .expect("disconnect callback called multiple times");
let _ = task_source.queue_with_canceller(trusted.resolve_task(()), &canceller); let _ = task_source.queue(trusted.resolve_task(()));
}), }),
); );
self.disconnect(sender); self.disconnect(sender);

View file

@ -201,22 +201,16 @@ impl XRSession {
fn setup_raf_loop(&self, frame_receiver: IpcReceiver<Frame>) { fn setup_raf_loop(&self, frame_receiver: IpcReceiver<Frame>) {
let this = Trusted::new(self); let this = Trusted::new(self);
let global = self.global(); let global = self.global();
let window = global.as_window(); let task_source = global.task_manager().dom_manipulation_task_source();
let (task_source, canceller) = window
.task_manager()
.dom_manipulation_task_source_with_canceller();
ROUTER.add_typed_route( ROUTER.add_typed_route(
frame_receiver, frame_receiver,
Box::new(move |message| { Box::new(move |message| {
let frame: Frame = message.unwrap(); let frame: Frame = message.unwrap();
let time = CrossProcessInstant::now(); let time = CrossProcessInstant::now();
let this = this.clone(); let this = this.clone();
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(xr_raf_callback: move || {
task!(xr_raf_callback: move || { this.root().raf_callback(frame, time);
this.root().raf_callback(frame, time); }));
}),
&canceller,
);
}), }),
); );
@ -230,22 +224,16 @@ impl XRSession {
fn attach_event_handler(&self) { fn attach_event_handler(&self) {
let this = Trusted::new(self); let this = Trusted::new(self);
let global = self.global(); let global = self.global();
let window = global.as_window(); let task_source = global.task_manager().dom_manipulation_task_source();
let (task_source, canceller) = window
.task_manager()
.dom_manipulation_task_source_with_canceller();
let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap(); let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap();
ROUTER.add_typed_route( ROUTER.add_typed_route(
receiver.to_ipc_receiver(), receiver.to_ipc_receiver(),
Box::new(move |message| { Box::new(move |message| {
let this = this.clone(); let this = this.clone();
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(xr_event_callback: move || {
task!(xr_event_callback: move || { this.root().event_callback(message.unwrap(), CanGc::note());
this.root().event_callback(message.unwrap(), CanGc::note()); }));
}),
&canceller,
);
}), }),
); );
@ -266,21 +254,14 @@ impl XRSession {
return; return;
} }
let global = self.global(); let task_source = self.global().task_manager().dom_manipulation_task_source();
let window = global.as_window();
let (task_source, canceller) = window
.task_manager()
.dom_manipulation_task_source_with_canceller();
let this = Trusted::new(self); let this = Trusted::new(self);
// Queue a task so that it runs after resolve()'s microtasks complete // Queue a task so that it runs after resolve()'s microtasks complete
// so that content has a chance to attach a listener for inputsourceschange // so that content has a chance to attach a listener for inputsourceschange
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(session_initial_inputs: move || {
task!(session_initial_inputs: move || { let this = this.root();
let this = this.root(); this.input_sources.add_input_sources(&this, &initial_inputs, CanGc::note());
this.input_sources.add_input_sources(&this, &initial_inputs, CanGc::note()); }));
}),
&canceller,
);
} }
fn event_callback(&self, event: XREvent, can_gc: CanGc) { fn event_callback(&self, event: XREvent, can_gc: CanGc) {
@ -1055,26 +1036,20 @@ impl XRSessionMethods<crate::DomTypeHolder> for XRSession {
let this = Trusted::new(self); let this = Trusted::new(self);
let global = self.global(); let global = self.global();
let window = global.as_window(); let task_source = global.task_manager().dom_manipulation_task_source();
let (task_source, canceller) = window
.task_manager()
.dom_manipulation_task_source_with_canceller();
let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap(); let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap();
ROUTER.add_typed_route( ROUTER.add_typed_route(
receiver.to_ipc_receiver(), receiver.to_ipc_receiver(),
Box::new(move |message| { Box::new(move |message| {
let this = this.clone(); let this = this.clone();
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(update_session_framerate: move || {
task!(update_session_framerate: move || { let session = this.root();
let session = this.root(); session.apply_nominal_framerate(message.unwrap(), CanGc::note());
session.apply_nominal_framerate(message.unwrap(), CanGc::note()); if let Some(promise) = session.update_framerate_promise.borrow_mut().take() {
if let Some(promise) = session.update_framerate_promise.borrow_mut().take() { promise.resolve_native(&());
promise.resolve_native(&()); };
}; }));
}),
&canceller,
);
}), }),
); );

View file

@ -118,10 +118,7 @@ impl XRSystemMethods<crate::DomTypeHolder> for XRSystem {
let promise = Promise::new(&self.global(), can_gc); let promise = Promise::new(&self.global(), can_gc);
let mut trusted = Some(TrustedPromise::new(promise.clone())); let mut trusted = Some(TrustedPromise::new(promise.clone()));
let global = self.global(); let global = self.global();
let window = global.as_window(); let task_source = global.task_manager().dom_manipulation_task_source();
let (task_source, canceller) = window
.task_manager()
.dom_manipulation_task_source_with_canceller();
let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap(); let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap();
ROUTER.add_typed_route( ROUTER.add_typed_route(
receiver.to_ipc_receiver(), receiver.to_ipc_receiver(),
@ -140,15 +137,13 @@ impl XRSystemMethods<crate::DomTypeHolder> for XRSystem {
return; return;
}; };
if let Ok(()) = message { if let Ok(()) = message {
let _ = let _ = task_source.queue(trusted.resolve_task(true));
task_source.queue_with_canceller(trusted.resolve_task(true), &canceller);
} else { } else {
let _ = let _ = task_source.queue(trusted.resolve_task(false));
task_source.queue_with_canceller(trusted.resolve_task(false), &canceller);
}; };
}), }),
); );
if let Some(mut r) = window.webxr_registry() { if let Some(mut r) = global.as_window().webxr_registry() {
r.supports_session(mode.convert(), sender); r.supports_session(mode.convert(), sender);
} }
@ -239,9 +234,7 @@ impl XRSystemMethods<crate::DomTypeHolder> for XRSystem {
let mut trusted = Some(TrustedPromise::new(promise.clone())); let mut trusted = Some(TrustedPromise::new(promise.clone()));
let this = Trusted::new(self); let this = Trusted::new(self);
let (task_source, canceller) = window let task_source = global.task_manager().dom_manipulation_task_source();
.task_manager()
.dom_manipulation_task_source_with_canceller();
let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap(); let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap();
let (frame_sender, frame_receiver) = ipc_crate::channel().unwrap(); let (frame_sender, frame_receiver) = ipc_crate::channel().unwrap();
let mut frame_receiver = Some(frame_receiver); let mut frame_receiver = Some(frame_receiver);
@ -258,12 +251,9 @@ impl XRSystemMethods<crate::DomTypeHolder> for XRSystem {
error!("requestSession callback given incorrect payload"); error!("requestSession callback given incorrect payload");
return; return;
}; };
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(request_session: move || {
task!(request_session: move || { this.root().session_obtained(message, trusted.root(), mode, frame_receiver);
this.root().session_obtained(message, trusted.root(), mode, frame_receiver); }));
}),
&canceller,
);
}), }),
); );
if let Some(mut r) = window.webxr_registry() { if let Some(mut r) = window.webxr_registry() {
@ -314,9 +304,7 @@ impl XRSystem {
// https://github.com/immersive-web/navigation/issues/10 // https://github.com/immersive-web/navigation/issues/10
pub fn dispatch_sessionavailable(&self) { pub fn dispatch_sessionavailable(&self) {
let xr = Trusted::new(self); let xr = Trusted::new(self);
let global = self.global(); self.global()
let window = global.as_window();
window
.task_manager() .task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue( .queue(
@ -327,8 +315,7 @@ impl XRSystem {
ScriptThread::set_user_interacting(true); ScriptThread::set_user_interacting(true);
xr.upcast::<EventTarget>().fire_bubbling_event(atom!("sessionavailable"), CanGc::note()); xr.upcast::<EventTarget>().fire_bubbling_event(atom!("sessionavailable"), CanGc::note());
ScriptThread::set_user_interacting(interacting); ScriptThread::set_user_interacting(interacting);
}), })
window.upcast(),
) )
.unwrap(); .unwrap();
} }

View file

@ -147,13 +147,10 @@ impl XRTestMethods<crate::DomTypeHolder> for XRTest {
}; };
let global = self.global(); let global = self.global();
let window = global.as_window();
let this = Trusted::new(self); let this = Trusted::new(self);
let mut trusted = Some(TrustedPromise::new(p.clone())); let mut trusted = Some(TrustedPromise::new(p.clone()));
let (task_source, canceller) = window let task_source = global.task_manager().dom_manipulation_task_source();
.task_manager()
.dom_manipulation_task_source_with_canceller();
let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap(); let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap();
ROUTER.add_typed_route( ROUTER.add_typed_route(
@ -166,15 +163,12 @@ impl XRTestMethods<crate::DomTypeHolder> for XRTest {
let message = let message =
message.expect("SimulateDeviceConnection callback given incorrect payload"); message.expect("SimulateDeviceConnection callback given incorrect payload");
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(request_session: move || {
task!(request_session: move || { this.root().device_obtained(message, trusted);
this.root().device_obtained(message, trusted); }));
}),
&canceller,
);
}), }),
); );
if let Some(mut r) = window.webxr_registry() { if let Some(mut r) = global.as_window().webxr_registry() {
r.simulate_device_connection(init, sender); r.simulate_device_connection(init, sender);
} }
@ -206,10 +200,7 @@ impl XRTestMethods<crate::DomTypeHolder> for XRTest {
devices.clear(); devices.clear();
let mut trusted = Some(TrustedPromise::new(p.clone())); let mut trusted = Some(TrustedPromise::new(p.clone()));
let (task_source, canceller) = global let task_source = global.task_manager().dom_manipulation_task_source();
.as_window()
.task_manager()
.dom_manipulation_task_source_with_canceller();
ROUTER.add_typed_route( ROUTER.add_typed_route(
receiver.to_ipc_receiver(), receiver.to_ipc_receiver(),
@ -219,8 +210,7 @@ impl XRTestMethods<crate::DomTypeHolder> for XRTest {
let trusted = trusted let trusted = trusted
.take() .take()
.expect("DisconnectAllDevices disconnected more devices than expected"); .expect("DisconnectAllDevices disconnected more devices than expected");
let _ = let _ = task_source.queue(trusted.resolve_task(()));
task_source.queue_with_canceller(trusted.resolve_task(()), &canceller);
} }
}), }),
); );

View file

@ -11,7 +11,6 @@ use std::default::Default;
use std::io::{stderr, stdout, Write}; use std::io::{stderr, stdout, Write};
use std::ptr::NonNull; use std::ptr::NonNull;
use std::rc::Rc; use std::rc::Rc;
use std::sync::atomic::Ordering;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@ -153,12 +152,9 @@ use crate::messaging::{
}; };
use crate::microtask::MicrotaskQueue; use crate::microtask::MicrotaskQueue;
use crate::realms::{enter_realm, InRealm}; use crate::realms::{enter_realm, InRealm};
use crate::script_runtime::{ use crate::script_runtime::{CanGc, JSContext, Runtime, ScriptChan, ScriptPort};
CanGc, CommonScriptMsg, JSContext, Runtime, ScriptChan, ScriptPort, ScriptThreadEventCategory,
};
use crate::script_thread::ScriptThread; use crate::script_thread::ScriptThread;
use crate::task_manager::TaskManager; use crate::task_manager::TaskManager;
use crate::task_source::TaskSourceName;
use crate::timers::{IsInterval, TimerCallback}; use crate::timers::{IsInterval, TimerCallback};
use crate::unminify::unminified_path; use crate::unminify::unminified_path;
use crate::webdriver_handlers::jsval_to_webdriver; use crate::webdriver_handlers::jsval_to_webdriver;
@ -208,7 +204,6 @@ pub struct Window {
globalscope: GlobalScope, globalscope: GlobalScope,
#[ignore_malloc_size_of = "trait objects are hard"] #[ignore_malloc_size_of = "trait objects are hard"]
script_chan: MainThreadScriptChan, script_chan: MainThreadScriptChan,
task_manager: TaskManager,
#[no_trace] #[no_trace]
#[ignore_malloc_size_of = "TODO: Add MallocSizeOf support to layout"] #[ignore_malloc_size_of = "TODO: Add MallocSizeOf support to layout"]
layout: RefCell<Box<dyn Layout>>, layout: RefCell<Box<dyn Layout>>,
@ -383,10 +378,6 @@ pub struct Window {
} }
impl Window { impl Window {
pub fn task_manager(&self) -> &TaskManager {
&self.task_manager
}
pub fn layout(&self) -> Ref<Box<dyn Layout>> { pub fn layout(&self) -> Ref<Box<dyn Layout>> {
self.layout.borrow() self.layout.borrow()
} }
@ -411,7 +402,8 @@ impl Window {
*self.js_runtime.borrow_for_script_deallocation() = None; *self.js_runtime.borrow_for_script_deallocation() = None;
self.window_proxy.set(None); self.window_proxy.set(None);
self.current_state.set(WindowState::Zombie); self.current_state.set(WindowState::Zombie);
self.ignore_all_tasks(); self.task_manager()
.cancel_all_tasks_and_ignore_future_tasks();
} }
} }
@ -426,16 +418,8 @@ impl Window {
// Step 4 of https://html.spec.whatwg.org/multipage/#discard-a-document // Step 4 of https://html.spec.whatwg.org/multipage/#discard-a-document
// Other steps performed when the `PipelineExit` message // Other steps performed when the `PipelineExit` message
// is handled by the ScriptThread. // is handled by the ScriptThread.
self.ignore_all_tasks(); self.task_manager()
} .cancel_all_tasks_and_ignore_future_tasks();
/// Cancel all current, and ignore all subsequently queued, tasks.
pub fn ignore_all_tasks(&self) {
let mut ignore_flags = self.task_manager.task_cancellers.borrow_mut();
for task_source_name in TaskSourceName::all() {
let flag = ignore_flags.entry(*task_source_name).or_default();
flag.store(true, Ordering::SeqCst);
}
} }
/// Get a sender to the time profiler thread. /// Get a sender to the time profiler thread.
@ -572,6 +556,10 @@ impl Window {
pub fn dispatch_event_with_target_override(&self, event: &Event, can_gc: CanGc) -> EventStatus { pub fn dispatch_event_with_target_override(&self, event: &Event, can_gc: CanGc) -> EventStatus {
event.dispatch(self.upcast(), true, can_gc) event.dispatch(self.upcast(), true, can_gc)
} }
pub(crate) fn task_manager(&self) -> &TaskManager {
self.upcast::<GlobalScope>().task_manager()
}
} }
// https://html.spec.whatwg.org/multipage/#atob // https://html.spec.whatwg.org/multipage/#atob
@ -825,9 +813,10 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
window.send_to_constellation(ScriptMsg::DiscardTopLevelBrowsingContext); window.send_to_constellation(ScriptMsg::DiscardTopLevelBrowsingContext);
} }
}); });
self.task_manager() self.global()
.task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue(task, self.upcast::<GlobalScope>()) .queue(task)
.expect("Queuing window_close_browsing_context task to work"); .expect("Queuing window_close_browsing_context task to work");
} }
} }
@ -1657,29 +1646,6 @@ impl Window {
self.document.get().is_some() self.document.get().is_some()
} }
/// Cancels all the tasks associated with that window.
///
/// This sets the current `task_manager.task_cancellers` sentinel value to
/// `true` and replaces it with a brand new one for future tasks.
pub fn cancel_all_tasks(&self) {
let mut ignore_flags = self.task_manager.task_cancellers.borrow_mut();
for task_source_name in TaskSourceName::all() {
let flag = ignore_flags.entry(*task_source_name).or_default();
let cancelled = std::mem::take(&mut *flag);
cancelled.store(true, Ordering::SeqCst);
}
}
/// Cancels all the tasks from a given task source.
/// This sets the current sentinel value to
/// `true` and replaces it with a brand new one for future tasks.
pub fn cancel_all_tasks_from_source(&self, task_source_name: TaskSourceName) {
let mut ignore_flags = self.task_manager.task_cancellers.borrow_mut();
let flag = ignore_flags.entry(task_source_name).or_default();
let cancelled = std::mem::take(&mut *flag);
cancelled.store(true, Ordering::SeqCst);
}
pub fn clear_js_runtime(&self) { pub fn clear_js_runtime(&self) {
self.upcast::<GlobalScope>() self.upcast::<GlobalScope>()
.remove_web_messaging_and_dedicated_workers_infra(); .remove_web_messaging_and_dedicated_workers_infra();
@ -1721,7 +1687,8 @@ impl Window {
if let Some(performance) = self.performance.get() { if let Some(performance) = self.performance.get() {
performance.clear_and_disable_performance_entry_buffer(); performance.clear_and_disable_performance_entry_buffer();
} }
self.ignore_all_tasks(); self.task_manager()
.cancel_all_tasks_and_ignore_future_tasks();
} }
/// <https://drafts.csswg.org/cssom-view/#dom-window-scroll> /// <https://drafts.csswg.org/cssom-view/#dom-window-scroll>
@ -2368,17 +2335,10 @@ impl Window {
CanGc::note()); CanGc::note());
event.upcast::<Event>().fire(this.upcast::<EventTarget>(), CanGc::note()); event.upcast::<Event>().fire(this.upcast::<EventTarget>(), CanGc::note());
}); });
// FIXME(nox): Why are errors silenced here? let _ = self
let _ = self.script_chan.send(CommonScriptMsg::Task( .task_manager()
ScriptThreadEventCategory::DomEvent, .dom_manipulation_task_source()
Box::new( .queue(task);
self.task_manager
.task_canceller(TaskSourceName::DOMManipulation)
.wrap_task(task),
),
Some(self.pipeline_id()),
TaskSourceName::DOMManipulation,
));
doc.set_url(load_data.url.clone()); doc.set_url(load_data.url.clone());
return; return;
} }
@ -2715,7 +2675,6 @@ impl Window {
pub(crate) fn new( pub(crate) fn new(
runtime: Rc<Runtime>, runtime: Rc<Runtime>,
script_chan: MainThreadScriptChan, script_chan: MainThreadScriptChan,
task_manager: TaskManager,
layout: Box<dyn Layout>, layout: Box<dyn Layout>,
image_cache_chan: Sender<ImageCacheMsg>, image_cache_chan: Sender<ImageCacheMsg>,
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
@ -2726,7 +2685,7 @@ impl Window {
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
constellation_chan: ScriptToConstellationChan, constellation_chan: ScriptToConstellationChan,
control_chan: IpcSender<ConstellationControlMsg>, control_chan: IpcSender<ConstellationControlMsg>,
pipelineid: PipelineId, pipeline_id: PipelineId,
parent_info: Option<PipelineId>, parent_info: Option<PipelineId>,
window_size: WindowSizeData, window_size: WindowSizeData,
origin: MutableOrigin, origin: MutableOrigin,
@ -2751,7 +2710,7 @@ impl Window {
inherited_secure_context: Option<bool>, inherited_secure_context: Option<bool>,
) -> DomRoot<Self> { ) -> DomRoot<Self> {
let error_reporter = CSSErrorReporter { let error_reporter = CSSErrorReporter {
pipelineid, pipelineid: pipeline_id,
script_chan: Arc::new(Mutex::new(control_chan)), script_chan: Arc::new(Mutex::new(control_chan)),
}; };
@ -2762,7 +2721,7 @@ impl Window {
let win = Box::new(Self { let win = Box::new(Self {
globalscope: GlobalScope::new_inherited( globalscope: GlobalScope::new_inherited(
pipelineid, pipeline_id,
devtools_chan, devtools_chan,
mem_profiler_chan, mem_profiler_chan,
time_profiler_chan, time_profiler_chan,
@ -2779,7 +2738,6 @@ impl Window {
unminify_js, unminify_js,
), ),
script_chan, script_chan,
task_manager,
layout: RefCell::new(layout), layout: RefCell::new(layout),
image_cache_chan, image_cache_chan,
image_cache, image_cache,
@ -2840,6 +2798,10 @@ impl Window {
unsafe { WindowBinding::Wrap(JSContext::from_ptr(runtime.cx()), win) } unsafe { WindowBinding::Wrap(JSContext::from_ptr(runtime.cx()), win) }
} }
pub(crate) fn event_loop_sender(&self) -> Box<dyn ScriptChan + Send> {
Box::new(self.script_chan.clone())
}
pub fn pipeline_id(&self) -> PipelineId { pub fn pipeline_id(&self) -> PipelineId {
self.upcast::<GlobalScope>().pipeline_id() self.upcast::<GlobalScope>().pipeline_id()
} }
@ -2983,19 +2945,11 @@ impl Window {
); );
} }
}); });
// FIXME(nox): Why are errors silenced here?
// TODO(#12718): Use the "posted message task source". // TODO(#12718): Use the "posted message task source".
// TODO: When switching to the right task source, update the task_canceller call too. let _ = self
let _ = self.script_chan.send(CommonScriptMsg::Task( .task_manager()
ScriptThreadEventCategory::DomEvent, .dom_manipulation_task_source()
Box::new( .queue(task);
self.task_manager
.task_canceller(TaskSourceName::DOMManipulation)
.wrap_task(task),
),
Some(self.pipeline_id()),
TaskSourceName::DOMManipulation,
));
} }
} }

View file

@ -220,12 +220,15 @@ impl WorkerMethods<crate::DomTypeHolder> for Worker {
let (control_sender, control_receiver) = unbounded(); let (control_sender, control_receiver) = unbounded();
let (context_sender, context_receiver) = unbounded(); let (context_sender, context_receiver) = unbounded();
let event_loop_sender = global
.event_loop_sender()
.expect("Tried to create a worker in a worker while not handling a message?");
let join_handle = DedicatedWorkerGlobalScope::run_worker_scope( let join_handle = DedicatedWorkerGlobalScope::run_worker_scope(
init, init,
worker_url, worker_url,
devtools_receiver, devtools_receiver,
worker_ref, worker_ref,
global.script_chan(), event_loop_sender,
sender, sender,
receiver, receiver,
worker_load_origin, worker_load_origin,

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::cell::{OnceCell, RefCell, RefMut}; use std::cell::{RefCell, RefMut};
use std::default::Default; use std::default::Default;
use std::rc::Rc; use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
@ -44,13 +44,12 @@ use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::{DomRoot, MutNullableDom}; use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::bindings::settings_stack::AutoEntryScript; use crate::dom::bindings::settings_stack::AutoEntryScript;
use crate::dom::bindings::str::{DOMString, USVString}; use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::bindings::trace::{CustomTraceable, RootedTraceableBox}; use crate::dom::bindings::trace::RootedTraceableBox;
use crate::dom::crypto::Crypto; use crate::dom::crypto::Crypto;
use crate::dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope; use crate::dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::performance::Performance; use crate::dom::performance::Performance;
use crate::dom::promise::Promise; use crate::dom::promise::Promise;
use crate::dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
#[cfg(feature = "webgpu")] #[cfg(feature = "webgpu")]
use crate::dom::webgpu::identityhub::IdentityHub; use crate::dom::webgpu::identityhub::IdentityHub;
use crate::dom::window::{base64_atob, base64_btoa}; use crate::dom::window::{base64_atob, base64_btoa};
@ -60,7 +59,6 @@ use crate::fetch;
use crate::realms::{enter_realm, InRealm}; use crate::realms::{enter_realm, InRealm};
use crate::script_runtime::{CanGc, CommonScriptMsg, JSContext, Runtime, ScriptChan, ScriptPort}; use crate::script_runtime::{CanGc, CommonScriptMsg, JSContext, Runtime, ScriptChan, ScriptPort};
use crate::task::TaskCanceller; use crate::task::TaskCanceller;
use crate::task_manager::TaskManager;
use crate::timers::{IsInterval, TimerCallback}; use crate::timers::{IsInterval, TimerCallback};
pub fn prepare_workerscope_init( pub fn prepare_workerscope_init(
@ -124,13 +122,10 @@ pub struct WorkerGlobalScope {
navigation_start: CrossProcessInstant, navigation_start: CrossProcessInstant,
performance: MutNullableDom<Performance>, performance: MutNullableDom<Performance>,
/// A [`TimerScheduler`] used to schedule timers for this [`ServiceWorkerGlobalScope`]. /// A [`TimerScheduler`] used to schedule timers for this [`WorkerGlobalScope`].
/// Timers are handled in the service worker event loop. /// Timers are handled in the service worker event loop.
#[no_trace] #[no_trace]
timer_scheduler: RefCell<TimerScheduler>, timer_scheduler: RefCell<TimerScheduler>,
/// A [`TaskManager`] for this [`WorkerGlobalScope`].
task_manager: OnceCell<TaskManager>,
} }
impl WorkerGlobalScope { impl WorkerGlobalScope {
@ -185,7 +180,6 @@ impl WorkerGlobalScope {
navigation_start: CrossProcessInstant::now(), navigation_start: CrossProcessInstant::now(),
performance: Default::default(), performance: Default::default(),
timer_scheduler: RefCell::default(), timer_scheduler: RefCell::default(),
task_manager: Default::default(),
} }
} }
@ -232,12 +226,6 @@ impl WorkerGlobalScope {
self.worker_id self.worker_id
} }
pub fn task_canceller(&self) -> TaskCanceller {
TaskCanceller {
cancelled: self.closing.clone(),
}
}
pub fn pipeline_id(&self) -> PipelineId { pub fn pipeline_id(&self) -> PipelineId {
self.globalscope.pipeline_id() self.globalscope.pipeline_id()
} }
@ -250,6 +238,14 @@ impl WorkerGlobalScope {
pub(crate) fn timer_scheduler(&self) -> RefMut<TimerScheduler> { pub(crate) fn timer_scheduler(&self) -> RefMut<TimerScheduler> {
self.timer_scheduler.borrow_mut() self.timer_scheduler.borrow_mut()
} }
/// Return a copy to the shared task canceller that is used to cancel all tasks
/// when this worker is closing.
pub(crate) fn shared_task_canceller(&self) -> TaskCanceller {
TaskCanceller {
cancelled: self.closing.clone(),
}
}
} }
impl WorkerGlobalScopeMethods<crate::DomTypeHolder> for WorkerGlobalScope { impl WorkerGlobalScopeMethods<crate::DomTypeHolder> for WorkerGlobalScope {
@ -495,23 +491,6 @@ impl WorkerGlobalScope {
} }
} }
pub fn script_chan(&self) -> Box<dyn ScriptChan + Send> {
let dedicated = self.downcast::<DedicatedWorkerGlobalScope>();
let service_worker = self.downcast::<ServiceWorkerGlobalScope>();
if let Some(dedicated) = dedicated {
dedicated.script_chan()
} else if let Some(service_worker) = service_worker {
return service_worker.script_chan();
} else {
panic!("need to implement a sender for SharedWorker")
}
}
pub(crate) fn task_manager(&self) -> &TaskManager {
self.task_manager
.get_or_init(|| TaskManager::new(self.script_chan(), self.pipeline_id()))
}
pub fn new_script_pair(&self) -> (Box<dyn ScriptChan + Send>, Box<dyn ScriptPort + Send>) { pub fn new_script_pair(&self) -> (Box<dyn ScriptChan + Send>, Box<dyn ScriptPort + Send>) {
let dedicated = self.downcast::<DedicatedWorkerGlobalScope>(); let dedicated = self.downcast::<DedicatedWorkerGlobalScope>();
if let Some(dedicated) = dedicated { if let Some(dedicated) = dedicated {
@ -542,5 +521,8 @@ impl WorkerGlobalScope {
pub fn close(&self) { pub fn close(&self) {
self.closing.store(true, Ordering::SeqCst); self.closing.store(true, Ordering::SeqCst);
self.upcast::<GlobalScope>()
.task_manager()
.cancel_all_tasks_and_ignore_future_tasks();
} }
} }

View file

@ -1566,6 +1566,7 @@ impl XMLHttpRequest {
sender, sender,
pipeline_id: global.pipeline_id(), pipeline_id: global.pipeline_id(),
name: TaskSourceName::Networking, name: TaskSourceName::Networking,
canceller: Default::default(),
}, },
Some(receiver), Some(receiver),
) )

View file

@ -26,10 +26,7 @@ pub fn generate_cache_listener_for_element<
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();
let window = elem.owner_window(); let task_source = elem.owner_window().task_manager().networking_task_source();
let (task_source, canceller) = window
.task_manager()
.networking_task_source_with_canceller();
let generation = elem.generation_id(); let generation = elem.generation_id();
ROUTER.add_typed_route( ROUTER.add_typed_route(
@ -38,16 +35,13 @@ pub fn generate_cache_listener_for_element<
let element = trusted_node.clone(); let element = trusted_node.clone();
let image: PendingImageResponse = message.unwrap(); let image: PendingImageResponse = message.unwrap();
debug!("Got image {:?}", image); debug!("Got image {:?}", image);
let _ = task_source.queue_with_canceller( let _ = task_source.queue(task!(process_image_response: move || {
task!(process_image_response: move || { let element = element.root();
let element = element.root(); // 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_id() {
if generation == element.generation_id() { element.process_image_response(image.response, CanGc::note());
element.process_image_response(image.response, CanGc::note()); }
} }));
}),
&canceller,
);
}), }),
); );

View file

@ -434,7 +434,7 @@ pub fn follow_hyperlink(
target_window target_window
.task_manager() .task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue(task, target_window.upcast()) .queue(task)
.unwrap(); .unwrap();
}; };
} }

View file

@ -16,7 +16,7 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::performanceentry::PerformanceEntry; use crate::dom::performanceentry::PerformanceEntry;
use crate::dom::performanceresourcetiming::{InitiatorType, PerformanceResourceTiming}; use crate::dom::performanceresourcetiming::{InitiatorType, PerformanceResourceTiming};
use crate::script_runtime::CanGc; use crate::script_runtime::CanGc;
use crate::task::{TaskCanceller, TaskOnce}; use crate::task::TaskOnce;
use crate::task_source::TaskSource; use crate::task_source::TaskSource;
/// An off-thread sink for async network event tasks. All such events are forwarded to /// An off-thread sink for async network event tasks. All such events are forwarded to
@ -24,7 +24,6 @@ use crate::task_source::TaskSource;
pub struct NetworkListener<Listener: PreInvoke + Send + 'static> { pub struct NetworkListener<Listener: PreInvoke + Send + 'static> {
pub context: Arc<Mutex<Listener>>, pub context: Arc<Mutex<Listener>>,
pub task_source: TaskSource, pub task_source: TaskSource,
pub canceller: Option<TaskCanceller>,
} }
pub trait ResourceTimingListener { pub trait ResourceTimingListener {
@ -75,15 +74,11 @@ pub fn submit_timing_data(
impl<Listener: PreInvoke + Send + 'static> NetworkListener<Listener> { impl<Listener: PreInvoke + Send + 'static> NetworkListener<Listener> {
pub fn notify<A: Action<Listener> + Send + 'static>(&self, action: A) { pub fn notify<A: Action<Listener> + Send + 'static>(&self, action: A) {
let task = ListenerTask { let result = self.task_source.queue(ListenerTask {
context: self.context.clone(), context: self.context.clone(),
action, action,
}; });
let result = if let Some(ref canceller) = self.canceller {
self.task_source.queue_with_canceller(task, canceller)
} else {
self.task_source.queue_unconditionally(task)
};
if let Err(err) = result { if let Err(err) = result {
warn!("failed to deliver network data: {:?}", err); warn!("failed to deliver network data: {:?}", err);
} }

View file

@ -75,7 +75,6 @@ use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingLi
use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; use crate::realms::{enter_realm, AlreadyInRealm, InRealm};
use crate::script_runtime::{CanGc, JSContext as SafeJSContext}; use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
use crate::task::TaskBox; use crate::task::TaskBox;
use crate::task_source::TaskSourceName;
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe fn gen_type_error(global: &GlobalScope, string: String) -> RethrowError { unsafe fn gen_type_error(global: &GlobalScope, string: String) -> RethrowError {
@ -1768,13 +1767,9 @@ fn fetch_single_module_script(
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource), resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
})); }));
let task_source = global.task_manager().networking_task_source();
let canceller = global.task_canceller(TaskSourceName::Networking);
let network_listener = NetworkListener { let network_listener = NetworkListener {
context, context,
task_source, task_source: global.task_manager().networking_task_source(),
canceller: Some(canceller),
}; };
match document { match document {
Some(document) => { Some(document) => {

View file

@ -399,8 +399,7 @@ unsafe extern "C" fn promise_rejection_tracker(
); );
event.upcast::<Event>().fire(&target, CanGc::note()); event.upcast::<Event>().fire(&target, CanGc::note());
}), })
global.upcast(),
).unwrap(); ).unwrap();
}, },
}; };
@ -455,7 +454,7 @@ unsafe extern "C" fn content_security_policy_allows(
global global
.task_manager() .task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue(task, &global) .queue(task)
.unwrap(); .unwrap();
} }
} }
@ -529,8 +528,7 @@ pub fn notify_about_rejected_promises(global: &GlobalScope) {
target.global().add_consumed_rejection(promise.reflector().get_jsobject().into_handle()); target.global().add_consumed_rejection(promise.reflector().get_jsobject().into_handle());
} }
} }
}), })
global.upcast(),
).unwrap(); ).unwrap();
} }
} }

View file

@ -152,7 +152,6 @@ use crate::script_runtime::{
CanGc, CommonScriptMsg, JSContext, Runtime, ScriptChan, ScriptThreadEventCategory, CanGc, CommonScriptMsg, JSContext, Runtime, ScriptChan, ScriptThreadEventCategory,
ThreadSafeJSContext, ThreadSafeJSContext,
}; };
use crate::task_manager::TaskManager;
use crate::task_queue::TaskQueue; use crate::task_queue::TaskQueue;
use crate::task_source::{TaskSource, TaskSourceName}; use crate::task_source::{TaskSource, TaskSourceName};
use crate::{devtools, webdriver_handlers}; use crate::{devtools, webdriver_handlers};
@ -693,7 +692,7 @@ impl ScriptThread {
global global
.task_manager() .task_manager()
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue(task, global.upcast()) .queue(task)
.expect("Enqueing navigate js task on the DOM manipulation task source failed"); .expect("Enqueing navigate js task on the DOM manipulation task source failed");
} else { } else {
if let Some(ref sender) = script_thread.senders.devtools_server_sender { if let Some(ref sender) = script_thread.senders.devtools_server_sender {
@ -907,6 +906,7 @@ impl ScriptThread {
sender: self_sender.as_boxed(), sender: self_sender.as_boxed(),
pipeline_id: state.id, pipeline_id: state.id,
name: TaskSourceName::Networking, name: TaskSourceName::Networking,
canceller: Default::default(),
})); }));
let cx = runtime.cx(); let cx = runtime.cx();
@ -1033,8 +1033,10 @@ impl ScriptThread {
fn prepare_for_shutdown_inner(&self) { fn prepare_for_shutdown_inner(&self) {
let docs = self.documents.borrow(); let docs = self.documents.borrow();
for (_, document) in docs.iter() { for (_, document) in docs.iter() {
let window = document.window(); document
window.ignore_all_tasks(); .window()
.task_manager()
.cancel_all_tasks_and_ignore_future_tasks();
} }
} }
@ -1407,6 +1409,7 @@ impl ScriptThread {
// //
// This task is empty because any new IPC messages in the ScriptThread trigger a // This task is empty because any new IPC messages in the ScriptThread trigger a
// rendering update when animations are not running. // rendering update when animations are not running.
let _realm = enter_realm(&*document);
let rendering_task_source = document.window().task_manager().rendering_task_source(); let rendering_task_source = document.window().task_manager().rendering_task_source();
let _ = let _ =
rendering_task_source.queue_unconditionally(task!(update_the_rendering: move || { })); rendering_task_source.queue_unconditionally(task!(update_the_rendering: move || { }));
@ -3129,10 +3132,6 @@ impl ScriptThread {
pipeline_id: incomplete.pipeline_id, pipeline_id: incomplete.pipeline_id,
}; };
let task_manager = TaskManager::new(
Box::new(self.senders.self_sender.clone()),
incomplete.pipeline_id,
);
let paint_time_metrics = PaintTimeMetrics::new( let paint_time_metrics = PaintTimeMetrics::new(
incomplete.pipeline_id, incomplete.pipeline_id,
self.senders.time_profiler_sender.clone(), self.senders.time_profiler_sender.clone(),
@ -3161,7 +3160,6 @@ impl ScriptThread {
let window = Window::new( let window = Window::new(
self.js_runtime.clone(), self.js_runtime.clone(),
self.senders.self_sender.clone(), self.senders.self_sender.clone(),
task_manager,
self.layout_factory.create(layout_config), self.layout_factory.create(layout_config),
self.senders.image_cache_sender.clone(), self.senders.image_cache_sender.clone(),
self.image_cache.clone(), self.image_cache.clone(),

View file

@ -67,15 +67,15 @@ impl fmt::Debug for dyn TaskBox {
} }
/// Encapsulated state required to create cancellable tasks from non-script threads. /// Encapsulated state required to create cancellable tasks from non-script threads.
#[derive(Clone)] #[derive(Clone, Default, JSTraceable, MallocSizeOf)]
pub struct TaskCanceller { pub struct TaskCanceller {
#[ignore_malloc_size_of = "This is difficult, because only one of them should be measured"]
pub cancelled: Arc<AtomicBool>, pub cancelled: Arc<AtomicBool>,
} }
impl TaskCanceller { impl TaskCanceller {
/// Returns a wrapped `task` that will be cancelled if the `TaskCanceller` /// Returns a wrapped `task` that will be cancelled if the `TaskCanceller` says so.
/// says so. pub(crate) fn wrap_task<T>(&self, task: T) -> impl TaskOnce
pub fn wrap_task<T>(&self, task: T) -> impl TaskOnce
where where
T: TaskOnce, T: TaskOnce,
{ {

View file

@ -2,110 +2,148 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use core::cell::RefCell;
use core::sync::atomic::Ordering;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use base::id::PipelineId; use base::id::PipelineId;
use crate::dom::bindings::cell::DomRefCell;
use crate::script_runtime::ScriptChan; use crate::script_runtime::ScriptChan;
use crate::task::TaskCanceller; use crate::task::TaskCanceller;
use crate::task_source::{TaskSource, TaskSourceName}; use crate::task_source::{TaskSource, TaskSourceName};
macro_rules! task_source_functions { #[derive(JSTraceable, MallocSizeOf)]
($self:ident, $task_source:ident) => { enum TaskCancellers {
pub(crate) fn $task_source(&$self) -> TaskSource { /// A shared canceller that is used for workers, which can create multiple TaskManagers, but all
$self.$task_source.clone() /// of them need to have the same canceller flag for all task sources.
} Shared(TaskCanceller),
}; /// For `Window` each `TaskSource` has its own canceller.
($self:ident, $with_canceller:ident, $task_source:ident) => { OnePerTaskSource(RefCell<HashMap<TaskSourceName, TaskCanceller>>),
pub(crate) fn $with_canceller(&$self) -> (TaskSource, TaskCanceller) { }
($self.$task_source.clone(), $self.task_canceller($self.$task_source.name))
}
impl TaskCancellers {
fn get(&self, name: TaskSourceName) -> TaskCanceller {
match self {
Self::Shared(canceller) => canceller.clone(),
Self::OnePerTaskSource(map) => map.borrow_mut().entry(name).or_default().clone(),
}
}
fn cancel_all_tasks_and_ignore_future_tasks(&self) {
match self {
Self::Shared(canceller) => canceller.cancelled.store(true, Ordering::SeqCst),
Self::OnePerTaskSource(..) => {
// We must create the canceller if they aren't created because we want future
// tasks to be ignored completely.
for task_source_name in TaskSourceName::all() {
self.get(*task_source_name)
.cancelled
.store(true, Ordering::SeqCst)
}
},
}
}
fn cancel_pending_tasks_for_source(&self, task_source_name: TaskSourceName) {
let Self::OnePerTaskSource(map) = self else {
unreachable!(
"It isn't possible to cancel pending tasks for Worker \
TaskManager's without ignoring future tasks."
)
};
// Remove the canceller from the map so that the next time a task like this is
// queued, it has a fresh, uncancelled canceller.
if let Some(canceller) = map.borrow_mut().remove(&task_source_name) {
// Cancel any tasks that use the current canceller.
canceller.cancelled.store(true, Ordering::SeqCst);
}
}
}
macro_rules! task_source_functions {
($self:ident, $task_source:ident, $task_source_name:ident) => {
pub(crate) fn $task_source(&$self) -> TaskSource { pub(crate) fn $task_source(&$self) -> TaskSource {
$self.$task_source.clone() $self.task_source_for_task_source_name(TaskSourceName::$task_source_name)
} }
}; };
} }
#[derive(JSTraceable, MallocSizeOf)] #[derive(JSTraceable, MallocSizeOf)]
pub struct TaskManager { pub struct TaskManager {
#[ignore_malloc_size_of = "task sources are hard"] #[ignore_malloc_size_of = "We need to push the measurement of this down into the ScriptChan trait"]
pub task_cancellers: DomRefCell<HashMap<TaskSourceName, Arc<AtomicBool>>>, sender: RefCell<Option<Box<dyn ScriptChan + Send>>>,
dom_manipulation_task_source: TaskSource, #[no_trace]
file_reading_task_source: TaskSource, pipeline_id: PipelineId,
gamepad_task_source: TaskSource, cancellers: TaskCancellers,
history_traversal_task_source: TaskSource,
media_element_task_source: TaskSource,
networking_task_source: TaskSource,
performance_timeline_task_source: TaskSource,
port_message_queue: TaskSource,
user_interaction_task_source: TaskSource,
remote_event_task_source: TaskSource,
rendering_task_source: TaskSource,
timer_task_source: TaskSource,
websocket_task_source: TaskSource,
} }
impl TaskManager { impl TaskManager {
#[allow(clippy::too_many_arguments)] pub(crate) fn new(
pub(crate) fn new(sender: Box<dyn ScriptChan + Send>, pipeline_id: PipelineId) -> Self { sender: Option<Box<dyn ScriptChan + Send>>,
let task_source = |name| TaskSource { pipeline_id: PipelineId,
sender: sender.as_boxed(), shared_canceller: Option<TaskCanceller>,
pipeline_id, ) -> Self {
name, let cancellers = match shared_canceller {
Some(shared_canceller) => TaskCancellers::Shared(shared_canceller),
None => TaskCancellers::OnePerTaskSource(Default::default()),
}; };
let sender = RefCell::new(sender);
TaskManager { TaskManager {
dom_manipulation_task_source: task_source(TaskSourceName::DOMManipulation), sender,
file_reading_task_source: task_source(TaskSourceName::FileReading), pipeline_id,
gamepad_task_source: task_source(TaskSourceName::Gamepad), cancellers,
history_traversal_task_source: task_source(TaskSourceName::HistoryTraversal),
media_element_task_source: task_source(TaskSourceName::MediaElement),
networking_task_source: task_source(TaskSourceName::Networking),
performance_timeline_task_source: task_source(TaskSourceName::PerformanceTimeline),
port_message_queue: task_source(TaskSourceName::PortMessage),
user_interaction_task_source: task_source(TaskSourceName::UserInteraction),
remote_event_task_source: task_source(TaskSourceName::RemoteEvent),
rendering_task_source: task_source(TaskSourceName::Rendering),
timer_task_source: task_source(TaskSourceName::Timer),
websocket_task_source: task_source(TaskSourceName::WebSocket),
task_cancellers: Default::default(),
} }
} }
task_source_functions!( fn task_source_for_task_source_name(&self, name: TaskSourceName) -> TaskSource {
self, let Some(sender) = self
dom_manipulation_task_source_with_canceller, .sender
dom_manipulation_task_source .borrow()
); .as_ref()
task_source_functions!(self, gamepad_task_source); .map(|sender| sender.as_boxed())
task_source_functions!( else {
self, unreachable!("Tried to enqueue task for DedicatedWorker while not handling a message.")
media_element_task_source_with_canceller, };
media_element_task_source
);
task_source_functions!(self, user_interaction_task_source);
task_source_functions!(
self,
networking_task_source_with_canceller,
networking_task_source
);
task_source_functions!(self, file_reading_task_source);
task_source_functions!(self, performance_timeline_task_source);
task_source_functions!(self, port_message_queue);
task_source_functions!(self, remote_event_task_source);
task_source_functions!(self, rendering_task_source);
task_source_functions!(self, timer_task_source);
task_source_functions!(self, websocket_task_source);
pub fn task_canceller(&self, name: TaskSourceName) -> TaskCanceller { TaskSource {
let mut flags = self.task_cancellers.borrow_mut(); sender,
let cancel_flag = flags.entry(name).or_default(); pipeline_id: self.pipeline_id,
TaskCanceller { name,
cancelled: cancel_flag.clone(), canceller: self.cancellers.get(name),
} }
} }
/// Update the sender for this [`TaskSource`]. This is used by dedicated workers, which only have a
/// sender while handling messages (as their sender prevents the main thread Worker object from being
/// garbage collected).
pub(crate) fn set_sender(&self, sender: Option<Box<dyn ScriptChan + Send>>) {
*self.sender.borrow_mut() = sender;
}
/// Cancel all queued but unexecuted tasks and ignore all subsequently queued tasks.
pub(crate) fn cancel_all_tasks_and_ignore_future_tasks(&self) {
self.cancellers.cancel_all_tasks_and_ignore_future_tasks();
}
/// Cancel all queued but unexecuted tasks for the given task source, but subsequently queued
/// tasks will not be ignored.
pub(crate) fn cancel_pending_tasks_for_source(&self, task_source_name: TaskSourceName) {
self.cancellers
.cancel_pending_tasks_for_source(task_source_name);
}
task_source_functions!(self, dom_manipulation_task_source, DOMManipulation);
task_source_functions!(self, file_reading_task_source, FileReading);
task_source_functions!(self, gamepad_task_source, Gamepad);
task_source_functions!(self, media_element_task_source, MediaElement);
task_source_functions!(self, networking_task_source, Networking);
task_source_functions!(self, performance_timeline_task_source, PerformanceTimeline);
task_source_functions!(self, port_message_queue, PortMessage);
task_source_functions!(self, remote_event_task_source, RemoteEvent);
task_source_functions!(self, rendering_task_source, Rendering);
task_source_functions!(self, timer_task_source, Timer);
task_source_functions!(self, user_interaction_task_source, UserInteraction);
task_source_functions!(self, websocket_task_source, WebSocket);
} }

View file

@ -9,12 +9,9 @@ use base::id::PipelineId;
use malloc_size_of_derive::MallocSizeOf; use malloc_size_of_derive::MallocSizeOf;
use servo_atoms::Atom; use servo_atoms::Atom;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::Trusted; use crate::dom::bindings::refcounted::Trusted;
use crate::dom::event::{EventBubbles, EventCancelable, EventTask, SimpleEventTask}; use crate::dom::event::{EventBubbles, EventCancelable, EventTask, SimpleEventTask};
use crate::dom::eventtarget::EventTarget; use crate::dom::eventtarget::EventTarget;
use crate::dom::types::GlobalScope;
use crate::dom::window::Window;
use crate::script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory}; use crate::script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory};
use crate::task::{TaskCanceller, TaskOnce}; use crate::task::{TaskCanceller, TaskOnce};
@ -92,34 +89,23 @@ pub(crate) struct TaskSource {
#[no_trace] #[no_trace]
pub pipeline_id: PipelineId, pub pipeline_id: PipelineId,
pub name: TaskSourceName, pub name: TaskSourceName,
pub canceller: TaskCanceller,
} }
impl TaskSource { impl TaskSource {
pub(crate) fn queue_with_canceller<T>( pub(crate) fn queue<T>(&self, task: T) -> Result<(), ()>
&self,
task: T,
canceller: &TaskCanceller,
) -> Result<(), ()>
where where
T: TaskOnce + 'static, T: TaskOnce + 'static,
{ {
let msg = CommonScriptMsg::Task( let msg = CommonScriptMsg::Task(
self.name.into(), self.name.into(),
Box::new(canceller.wrap_task(task)), Box::new(self.canceller.wrap_task(task)),
Some(self.pipeline_id), Some(self.pipeline_id),
self.name, self.name,
); );
self.sender.send(msg).map_err(|_| ()) self.sender.send(msg).map_err(|_| ())
} }
pub(crate) fn queue<T>(&self, task: T, global: &GlobalScope) -> Result<(), ()>
where
T: TaskOnce + 'static,
{
let canceller = global.task_canceller(self.name);
self.queue_with_canceller(task, &canceller)
}
/// This queues a task that will not be cancelled when its associated global scope gets destroyed. /// This queues a task that will not be cancelled when its associated global scope gets destroyed.
pub(crate) fn queue_unconditionally<T>(&self, task: T) -> Result<(), ()> pub(crate) fn queue_unconditionally<T>(&self, task: T) -> Result<(), ()>
where where
@ -133,9 +119,9 @@ impl TaskSource {
)) ))
} }
pub(crate) fn queue_simple_event(&self, target: &EventTarget, name: Atom, window: &Window) { pub(crate) fn queue_simple_event(&self, target: &EventTarget, name: Atom) {
let target = Trusted::new(target); let target = Trusted::new(target);
let _ = self.queue(SimpleEventTask { target, name }, window.upcast()); let _ = self.queue(SimpleEventTask { target, name });
} }
pub(crate) fn queue_event( pub(crate) fn queue_event(
@ -144,16 +130,14 @@ impl TaskSource {
name: Atom, name: Atom,
bubbles: EventBubbles, bubbles: EventBubbles,
cancelable: EventCancelable, cancelable: EventCancelable,
window: &Window,
) { ) {
let target = Trusted::new(target); let target = Trusted::new(target);
let task = EventTask { let _ = self.queue(EventTask {
target, target,
name, name,
bubbles, bubbles,
cancelable, cancelable,
}; });
let _ = self.queue(task, window.upcast());
} }
} }
@ -163,6 +147,7 @@ impl Clone for TaskSource {
sender: self.sender.as_boxed(), sender: self.sender.as_boxed(),
pipeline_id: self.pipeline_id, pipeline_id: self.pipeline_id,
name: self.name, name: self.name,
canceller: self.canceller.clone(),
} }
} }
} }