Unify the task source and task canceller API

I moved away from the `Window` struct all the logic to handle task
sources, into a new struct called `TaskManager`. In a happy world, I'd
be able to just have there two functions, of the types:

```rust
fn task_source<T: TaskSource>(&self, name: TaskSourceName) -> Box<T>
fn task_source_with_canceller<T: TaskSource>(&self, name: TaskSourceName)
  -> (Box<T>, TaskSourceCanceller)
```

And not so much duplicated code. However, because TaskSource can't be a
trait object (because it has generic type parameters), that's not
possible. Instead, I decided to reduce duplicated logic through macros.

For reasons[1], I have to pass both the name of the function with
canceller and the name of the function without, as I'm not able to
concatenate them in the macro itself. I could probably use
`concat_idents` to create both types already defined and reduce the
amount of arguments by one, but that macro is nightly only. At the same
time, not being able to declare macros inside `impl` forces me to pass
`self` as an argument.

All this makes this solution more verbose than it would be ideally. It
does reduce duplication, but it doesn't reduce the size of the file.

[1](https://github.com/rust-lang/rust/issues/29599)
This commit is contained in:
Agustin Chiappe Berrini 2018-09-24 19:31:59 -04:00
parent 14bc8ab754
commit 75eb94afca
26 changed files with 362 additions and 252 deletions

View file

@ -17,7 +17,7 @@ use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::reflect_dom_object;
use crate::dom::bindings::root::DomRoot;
use crate::dom::window::Window;
use crate::task_source::{TaskSource, TaskSourceName};
use crate::task_source::TaskSource;
use dom_struct::dom_struct;
use ipc_channel::ipc::{self, IpcReceiver};
use ipc_channel::router::ROUTER;
@ -97,8 +97,9 @@ impl AnalyserNode {
) -> Fallible<DomRoot<AnalyserNode>> {
let (node, recv) = AnalyserNode::new_inherited(window, context, options)?;
let object = reflect_dom_object(Box::new(node), window, AnalyserNodeBinding::Wrap);
let source = window.dom_manipulation_task_source();
let canceller = window.task_canceller(TaskSourceName::DOMManipulation);
let (source, canceller) = window
.task_manager()
.dom_manipulation_task_source_with_canceller();
let this = Trusted::new(&*object);
ROUTER.add_route(

View file

@ -126,7 +126,7 @@ impl AudioContextMethods for AudioContext {
// Steps 4 and 5.
let window = DomRoot::downcast::<Window>(self.global()).unwrap();
let task_source = window.dom_manipulation_task_source();
let task_source = window.task_manager().dom_manipulation_task_source();
let trusted_promise = TrustedPromise::new(promise.clone());
match self.context.audio_context_impl().suspend() {
Ok(_) => {
@ -141,7 +141,7 @@ impl AudioContextMethods for AudioContext {
if base_context.State() != AudioContextState::Suspended {
base_context.set_state_attribute(AudioContextState::Suspended);
let window = DomRoot::downcast::<Window>(context.global()).unwrap();
window.dom_manipulation_task_source().queue_simple_event(
window.task_manager().dom_manipulation_task_source().queue_simple_event(
context.upcast(),
atom!("statechange"),
&window
@ -188,7 +188,7 @@ impl AudioContextMethods for AudioContext {
// Steps 4 and 5.
let window = DomRoot::downcast::<Window>(self.global()).unwrap();
let task_source = window.dom_manipulation_task_source();
let task_source = window.task_manager().dom_manipulation_task_source();
let trusted_promise = TrustedPromise::new(promise.clone());
match self.context.audio_context_impl().close() {
Ok(_) => {
@ -203,7 +203,7 @@ impl AudioContextMethods for AudioContext {
if base_context.State() != AudioContextState::Closed {
base_context.set_state_attribute(AudioContextState::Closed);
let window = DomRoot::downcast::<Window>(context.global()).unwrap();
window.dom_manipulation_task_source().queue_simple_event(
window.task_manager().dom_manipulation_task_source().queue_simple_event(
context.upcast(),
atom!("statechange"),
&window

View file

@ -10,7 +10,7 @@ use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::DomObject;
use crate::task_source::{TaskSource, TaskSourceName};
use crate::task_source::TaskSource;
use dom_struct::dom_struct;
use servo_media::audio::node::OnEndedCallback;
use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage, AudioScheduledSourceNodeMessage};
@ -71,15 +71,16 @@ impl AudioScheduledSourceNodeMethods for AudioScheduledSourceNode {
let this = Trusted::new(self);
let global = self.global();
let window = global.as_window();
let task_source = window.dom_manipulation_task_source();
let canceller = window.task_canceller(TaskSourceName::DOMManipulation);
let (task_source, canceller) = window
.task_manager()
.dom_manipulation_task_source_with_canceller();
let callback = OnEndedCallback::new(move || {
let _ = task_source.queue_with_canceller(
task!(ended: move || {
let this = this.root();
let global = this.global();
let window = global.as_window();
window.dom_manipulation_task_source().queue_simple_event(
window.task_manager().dom_manipulation_task_source().queue_simple_event(
this.upcast(),
atom!("ended"),
&window

View file

@ -40,7 +40,7 @@ use crate::dom::oscillatornode::OscillatorNode;
use crate::dom::pannernode::PannerNode;
use crate::dom::promise::Promise;
use crate::dom::window::Window;
use crate::task_source::{TaskSource, TaskSourceName};
use crate::task_source::TaskSource;
use dom_struct::dom_struct;
use js::rust::CustomAutoRooterGuard;
use js::typedarray::ArrayBuffer;
@ -213,7 +213,7 @@ impl BaseAudioContext {
pub fn resume(&self) {
let global = self.global();
let window = global.as_window();
let task_source = window.dom_manipulation_task_source();
let task_source = window.task_manager().dom_manipulation_task_source();
let this = Trusted::new(self);
// Set the rendering thread state to 'running' and start
// rendering the audio graph.
@ -227,7 +227,7 @@ impl BaseAudioContext {
if this.state.get() != AudioContextState::Running {
this.state.set(AudioContextState::Running);
let window = DomRoot::downcast::<Window>(this.global()).unwrap();
window.dom_manipulation_task_source().queue_simple_event(
window.task_manager().dom_manipulation_task_source().queue_simple_event(
this.upcast(),
atom!("statechange"),
&window
@ -428,10 +428,12 @@ impl BaseAudioContextMethods for BaseAudioContext {
let decoded_audio__ = decoded_audio.clone();
let this = Trusted::new(self);
let this_ = this.clone();
let task_source = window.dom_manipulation_task_source();
let task_source_ = window.dom_manipulation_task_source();
let canceller = window.task_canceller(TaskSourceName::DOMManipulation);
let canceller_ = window.task_canceller(TaskSourceName::DOMManipulation);
let (task_source, canceller) = window
.task_manager()
.dom_manipulation_task_source_with_canceller();
let (task_source_, canceller_) = window
.task_manager()
.dom_manipulation_task_source_with_canceller();
let callbacks = AudioDecoderCallbacks::new()
.ready(move |channel_count| {
decoded_audio

View file

@ -521,6 +521,7 @@ impl Document {
if self.ready_state.get() == DocumentReadyState::Complete {
let document = Trusted::new(self);
self.window
.task_manager()
.dom_manipulation_task_source()
.queue(
task!(fire_pageshow_event: move || {
@ -1869,6 +1870,7 @@ impl Document {
debug!("Document loads are complete.");
let document = Trusted::new(self);
self.window
.task_manager()
.dom_manipulation_task_source()
.queue(
task!(fire_load_event: move || {
@ -1922,6 +1924,7 @@ impl Document {
let document = Trusted::new(self);
if document.root().browsing_context().is_some() {
self.window
.task_manager()
.dom_manipulation_task_source()
.queue(
task!(fire_pageshow_event: move || {
@ -2104,13 +2107,16 @@ impl Document {
// Step 4.1.
let window = self.window();
window.dom_manipulation_task_source().queue_event(
self.upcast(),
atom!("DOMContentLoaded"),
EventBubbles::Bubbles,
EventCancelable::NotCancelable,
window,
);
window
.task_manager()
.dom_manipulation_task_source()
.queue_event(
self.upcast(),
atom!("DOMContentLoaded"),
EventBubbles::Bubbles,
EventCancelable::NotCancelable,
window,
);
window.reflow(ReflowGoal::Full, ReflowReason::DOMContentLoaded);
update_with_current_time_ms(&self.dom_content_loaded_event_end);

View file

@ -476,7 +476,7 @@ impl GlobalScope {
/// this global scope.
pub fn networking_task_source(&self) -> NetworkingTaskSource {
if let Some(window) = self.downcast::<Window>() {
return window.networking_task_source();
return window.task_manager().networking_task_source();
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.networking_task_source();
@ -488,7 +488,7 @@ impl GlobalScope {
/// this global scope.
pub fn remote_event_task_source(&self) -> RemoteEventTaskSource {
if let Some(window) = self.downcast::<Window>() {
return window.remote_event_task_source();
return window.task_manager().remote_event_task_source();
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.remote_event_task_source();
@ -500,7 +500,7 @@ impl GlobalScope {
/// this global scope.
pub fn websocket_task_source(&self) -> WebsocketTaskSource {
if let Some(window) = self.downcast::<Window>() {
return window.websocket_task_source();
return window.task_manager().websocket_task_source();
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.websocket_task_source();
@ -635,7 +635,7 @@ impl GlobalScope {
/// 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_canceller(name);
return window.task_manager().task_canceller(name);
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
// Note: the "name" is not passed to the worker,
@ -691,7 +691,7 @@ impl GlobalScope {
pub fn dom_manipulation_task_source(&self) -> DOMManipulationTaskSource {
if let Some(window) = self.downcast::<Window>() {
return window.dom_manipulation_task_source();
return window.task_manager().dom_manipulation_task_source();
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.dom_manipulation_task_source();
@ -703,7 +703,7 @@ impl GlobalScope {
/// this of this global scope.
pub fn file_reading_task_source(&self) -> FileReadingTaskSource {
if let Some(window) = self.downcast::<Window>() {
return window.file_reading_task_source();
return window.task_manager().file_reading_task_source();
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.file_reading_task_source();
@ -756,7 +756,7 @@ impl GlobalScope {
/// of this global scope.
pub fn performance_timeline_task_source(&self) -> PerformanceTimelineTaskSource {
if let Some(window) = self.downcast::<Window>() {
return window.performance_timeline_task_source();
return window.task_manager().performance_timeline_task_source();
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.performance_timeline_task_source();

View file

@ -76,7 +76,7 @@ impl VirtualMethods for HTMLDetailsElement {
let window = window_from_node(self);
let this = Trusted::new(self);
// FIXME(nox): Why are errors silenced here?
let _ = window.dom_manipulation_task_source().queue(
let _ = window.task_manager().dom_manipulation_task_source().queue(
task!(details_notification_task_steps: move || {
let this = this.root();
if counter == this.toggle_counter.get() {

View file

@ -90,7 +90,8 @@ impl HTMLDialogElementMethods for HTMLDialogElement {
// TODO: Step 4 implement pending dialog stack removal
// Step 5
win.dom_manipulation_task_source()
win.task_manager()
.dom_manipulation_task_source()
.queue_simple_event(target, atom!("close"), &win);
}
}

View file

@ -523,6 +523,7 @@ impl HTMLFormElement {
// Step 3.
target
.task_manager()
.dom_manipulation_task_source()
.queue(task, target.upcast())
.unwrap();

View file

@ -237,7 +237,7 @@ impl HTMLIFrameElement {
let this = Trusted::new(self);
let pipeline_id = self.pipeline_id().unwrap();
// FIXME(nox): Why are errors silenced here?
let _ = window.dom_manipulation_task_source().queue(
let _ = window.task_manager().dom_manipulation_task_source().queue(
task!(iframe_load_event_steps: move || {
this.root().iframe_load_event_steps(pipeline_id);
}),

View file

@ -40,7 +40,7 @@ use crate::dom::window::Window;
use crate::microtask::{Microtask, MicrotaskRunnable};
use crate::network_listener::{NetworkListener, PreInvoke};
use crate::script_thread::ScriptThread;
use crate::task_source::{TaskSource, TaskSourceName};
use crate::task_source::TaskSource;
use cssparser::{Parser, ParserInput};
use dom_struct::dom_struct;
use euclid::Point2D;
@ -237,8 +237,9 @@ impl HTMLImageElement {
let (responder_sender, responder_receiver) = ipc::channel().unwrap();
let window = window_from_node(elem);
let task_source = window.networking_task_source();
let task_canceller = window.task_canceller(TaskSourceName::Networking);
let (task_source, canceller) = window
.task_manager()
.networking_task_source_with_canceller();
let generation = elem.generation.get();
ROUTER.add_route(
responder_receiver.to_opaque(),
@ -257,7 +258,7 @@ impl HTMLImageElement {
element.process_image_response(image);
}
}),
&task_canceller,
&canceller,
);
}),
);
@ -308,10 +309,14 @@ impl HTMLImageElement {
}));
let (action_sender, action_receiver) = ipc::channel().unwrap();
let (task_source, canceller) = document
.window()
.task_manager()
.networking_task_source_with_canceller();
let listener = NetworkListener {
context: context,
task_source: window.networking_task_source(),
canceller: Some(window.task_canceller(TaskSourceName::Networking)),
context,
task_source,
canceller: Some(canceller),
};
ROUTER.add_route(
action_receiver.to_opaque(),
@ -780,7 +785,7 @@ impl HTMLImageElement {
fn update_the_image_data_sync_steps(&self) {
let document = document_from_node(self);
let window = document.window();
let task_source = window.dom_manipulation_task_source();
let task_source = window.task_manager().dom_manipulation_task_source();
let this = Trusted::new(self);
let (src, pixel_density) = match self.select_image_source() {
// Step 8
@ -938,7 +943,7 @@ impl HTMLImageElement {
current_request.current_pixel_density = pixel_density;
let this = Trusted::new(self);
let src = String::from(src);
let _ = window.dom_manipulation_task_source().queue(
let _ = window.task_manager().dom_manipulation_task_source().queue(
task!(image_load_event: move || {
let this = this.root();
{
@ -989,8 +994,9 @@ impl HTMLImageElement {
let (responder_sender, responder_receiver) = ipc::channel().unwrap();
let window = window_from_node(elem);
let task_source = window.networking_task_source();
let task_canceller = window.task_canceller(TaskSourceName::Networking);
let (task_source, canceller) = window
.task_manager()
.networking_task_source_with_canceller();
let generation = elem.generation.get();
ROUTER.add_route(responder_receiver.to_opaque(), Box::new(move |message| {
debug!("Got image {:?}", message);
@ -1008,7 +1014,7 @@ impl HTMLImageElement {
DOMString::from_string(selected_source_clone), generation, selected_pixel_density);
}
}),
&task_canceller,
&canceller,
);
}));
@ -1133,7 +1139,7 @@ impl HTMLImageElement {
let this = Trusted::new(self);
let window = window_from_node(self);
let src = src.to_string();
let _ = window.dom_manipulation_task_source().queue(
let _ = window.task_manager().dom_manipulation_task_source().queue(
task!(image_load_event: move || {
let this = this.root();
let relevant_mutation = this.generation.get() != generation;

View file

@ -1515,13 +1515,16 @@ impl VirtualMethods for HTMLInputElement {
{
if event.IsTrusted() {
let window = window_from_node(self);
let _ = window.user_interaction_task_source().queue_event(
&self.upcast(),
atom!("input"),
EventBubbles::Bubbles,
EventCancelable::NotCancelable,
&window,
);
let _ = window
.task_manager()
.user_interaction_task_source()
.queue_event(
&self.upcast(),
atom!("input"),
EventBubbles::Bubbles,
EventCancelable::NotCancelable,
&window,
);
}
}
}

View file

@ -36,7 +36,7 @@ use crate::fetch::FetchCanceller;
use crate::microtask::{Microtask, MicrotaskRunnable};
use crate::network_listener::{NetworkListener, PreInvoke};
use crate::script_thread::ScriptThread;
use crate::task_source::{TaskSource, TaskSourceName};
use crate::task_source::TaskSource;
use dom_struct::dom_struct;
use headers_core::HeaderMapExt;
use headers_ext::ContentLength;
@ -295,7 +295,7 @@ impl HTMLMediaElement {
let window = window_from_node(self);
// FIXME(nox): Why are errors silenced here?
let task_source = window.media_element_task_source();
let task_source = window.task_manager().media_element_task_source();
if self.Paused() {
// Step 6.1.
self.paused.set(false);
@ -373,7 +373,7 @@ impl HTMLMediaElement {
let window = window_from_node(self);
let this = Trusted::new(self);
let generation_id = self.generation_id.get();
let _ = window.media_element_task_source().queue(
let _ = window.task_manager().media_element_task_source().queue(
task!(internal_pause_steps: move || {
let this = this.root();
if generation_id != this.generation_id.get() {
@ -415,7 +415,7 @@ impl HTMLMediaElement {
let this = Trusted::new(self);
let generation_id = self.generation_id.get();
// FIXME(nox): Why are errors silenced here?
let _ = window.media_element_task_source().queue(
let _ = window.task_manager().media_element_task_source().queue(
task!(notify_about_playing: move || {
let this = this.root();
if generation_id != this.generation_id.get() {
@ -449,7 +449,7 @@ impl HTMLMediaElement {
}
let window = window_from_node(self);
let task_source = window.media_element_task_source();
let task_source = window.task_manager().media_element_task_source();
// Step 1.
match (old_ready_state, ready_state) {
@ -604,11 +604,10 @@ impl HTMLMediaElement {
// Step 8.
let window = window_from_node(self);
window.media_element_task_source().queue_simple_event(
self.upcast(),
atom!("loadstart"),
&window,
);
window
.task_manager()
.media_element_task_source()
.queue_simple_event(self.upcast(), atom!("loadstart"), &window);
// Step 9.
match mode {
@ -710,10 +709,13 @@ impl HTMLMediaElement {
let context = Arc::new(Mutex::new(HTMLMediaElementContext::new(self)));
let (action_sender, action_receiver) = ipc::channel().unwrap();
let window = window_from_node(self);
let (task_source, canceller) = window
.task_manager()
.networking_task_source_with_canceller();
let listener = NetworkListener {
context,
task_source: window.networking_task_source(),
canceller: Some(window.task_canceller(TaskSourceName::Networking)),
task_source,
canceller: Some(canceller),
};
ROUTER.add_route(
action_receiver.to_opaque(),
@ -768,15 +770,15 @@ impl HTMLMediaElement {
// Step 4.remote.1.2.
let window = window_from_node(self);
window.media_element_task_source().queue_simple_event(
self.upcast(),
atom!("suspend"),
&window,
);
window
.task_manager()
.media_element_task_source()
.queue_simple_event(self.upcast(), atom!("suspend"), &window);
// Step 4.remote.1.3.
let this = Trusted::new(self);
window
.task_manager()
.media_element_task_source()
.queue(
task!(set_media_delay_load_event_flag_to_false: move || {
@ -817,7 +819,7 @@ impl HTMLMediaElement {
let generation_id = self.generation_id.get();
self.take_pending_play_promises(Err(Error::NotSupported));
// FIXME(nox): Why are errors silenced here?
let _ = window.media_element_task_source().queue(
let _ = window.task_manager().media_element_task_source().queue(
task!(dedicated_media_source_failure_steps: move || {
let this = this.root();
if generation_id != this.generation_id.get() {
@ -874,7 +876,7 @@ impl HTMLMediaElement {
}
let window = window_from_node(self);
let task_source = window.media_element_task_source();
let task_source = window.task_manager().media_element_task_source();
// Step 5.
let network_state = self.network_state.get();
@ -1051,7 +1053,7 @@ impl HTMLMediaElement {
// Step 10.
let window = window_from_node(self);
let task_source = window.media_element_task_source();
let task_source = window.task_manager().media_element_task_source();
task_source.queue_simple_event(self.upcast(), atom!("seeking"), &window);
// Step 11.
@ -1074,7 +1076,7 @@ impl HTMLMediaElement {
// Step 16.
let window = window_from_node(self);
let task_source = window.media_element_task_source();
let task_source = window.task_manager().media_element_task_source();
task_source.queue_simple_event(self.upcast(), atom!("timeupdate"), &window);
// Step 17.
@ -1090,8 +1092,9 @@ impl HTMLMediaElement {
let trusted_node = Trusted::new(self);
let window = window_from_node(self);
let task_source = window.media_element_task_source();
let task_canceller = window.task_canceller(TaskSourceName::DOMManipulation);
let (task_source, canceller) = window
.task_manager()
.dom_manipulation_task_source_with_canceller();
ROUTER.add_route(
action_receiver.to_opaque(),
Box::new(move |message| {
@ -1102,7 +1105,7 @@ impl HTMLMediaElement {
task!(handle_player_event: move || {
this.root().handle_player_event(&event);
}),
&task_canceller,
&canceller,
)
.unwrap();
}),
@ -1134,7 +1137,7 @@ impl HTMLMediaElement {
}
if previous_duration != self.duration.get() {
let window = window_from_node(self);
let task_source = window.media_element_task_source();
let task_source = window.task_manager().media_element_task_source();
task_source.queue_simple_event(self.upcast(), atom!("durationchange"), &window);
}
@ -1147,7 +1150,7 @@ impl HTMLMediaElement {
video_elem.set_video_width(metadata.width);
video_elem.set_video_height(metadata.height);
let window = window_from_node(self);
let task_source = window.media_element_task_source();
let task_source = window.task_manager().media_element_task_source();
task_source.queue_simple_event(self.upcast(), atom!("resize"), &window);
}
}
@ -1515,11 +1518,10 @@ impl FetchResponseListener for HTMLMediaElementContext {
// => "If mode is remote" step 2
if time::get_time() > self.next_progress_event {
let window = window_from_node(&*elem);
window.media_element_task_source().queue_simple_event(
elem.upcast(),
atom!("progress"),
&window,
);
window
.task_manager()
.media_element_task_source()
.queue_simple_event(elem.upcast(), atom!("progress"), &window);
self.next_progress_event = time::get_time() + Duration::milliseconds(350);
}
}

View file

@ -25,7 +25,6 @@ use crate::dom::node::{document_from_node, window_from_node};
use crate::dom::node::{ChildrenMutation, CloneChildrenFlag, Node};
use crate::dom::virtualmethods::VirtualMethods;
use crate::network_listener::{NetworkListener, PreInvoke};
use crate::task_source::TaskSourceName;
use dom_struct::dom_struct;
use encoding_rs::Encoding;
use html5ever::{LocalName, Prefix};
@ -294,10 +293,14 @@ fn fetch_a_classic_script(
}));
let (action_sender, action_receiver) = ipc::channel().unwrap();
let (task_source, canceller) = doc
.window()
.task_manager()
.networking_task_source_with_canceller();
let listener = NetworkListener {
context: context,
task_source: doc.window().networking_task_source(),
canceller: Some(doc.window().task_canceller(TaskSourceName::Networking)),
context,
task_source,
canceller: Some(canceller),
};
ROUTER.add_route(
@ -623,11 +626,10 @@ impl HTMLScriptElement {
pub fn queue_error_event(&self) {
let window = window_from_node(self);
window.dom_manipulation_task_source().queue_simple_event(
self.upcast(),
atom!("error"),
&window,
);
window
.task_manager()
.dom_manipulation_task_source()
.queue_simple_event(self.upcast(), atom!("error"), &window);
}
pub fn dispatch_load_event(&self) {

View file

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

View file

@ -565,13 +565,16 @@ impl VirtualMethods for HTMLTextAreaElement {
} else if event.type_() == atom!("keypress") && !event.DefaultPrevented() {
if event.IsTrusted() {
let window = window_from_node(self);
let _ = window.user_interaction_task_source().queue_event(
&self.upcast(),
atom!("input"),
EventBubbles::Bubbles,
EventCancelable::NotCancelable,
&window,
);
let _ = window
.task_manager()
.user_interaction_task_source()
.queue_event(
&self.upcast(),
atom!("input"),
EventBubbles::Bubbles,
EventCancelable::NotCancelable,
&window,
);
}
}
}

View file

@ -20,7 +20,7 @@ use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::offlineaudiocompletionevent::OfflineAudioCompletionEvent;
use crate::dom::promise::Promise;
use crate::dom::window::Window;
use crate::task_source::{TaskSource, TaskSourceName};
use crate::task_source::TaskSource;
use dom_struct::dom_struct;
use servo_media::audio::context::OfflineAudioContextOptions as ServoMediaOfflineAudioContextOptions;
use std::cell::Cell;
@ -141,8 +141,9 @@ impl OfflineAudioContextMethods for OfflineAudioContext {
let this = Trusted::new(self);
let global = self.global();
let window = global.as_window();
let task_source = window.dom_manipulation_task_source();
let canceller = window.task_canceller(TaskSourceName::DOMManipulation);
let (task_source, canceller) = window
.task_manager()
.dom_manipulation_task_source_with_canceller();
Builder::new()
.name("OfflineAudioContextResolver".to_owned())
.spawn(move || {

View file

@ -209,6 +209,7 @@ impl Storage {
let this = Trusted::new(self);
global
.as_window()
.task_manager()
.dom_manipulation_task_source()
.queue(
task!(send_storage_notification: move || {

View file

@ -297,13 +297,16 @@ impl<'a, E: TextControlElement> TextControlSelection<'a, E> {
// Step 6
if textinput.selection_state() != original_selection_state {
let window = window_from_node(self.element);
window.user_interaction_task_source().queue_event(
&self.element.upcast::<EventTarget>(),
atom!("select"),
EventBubbles::Bubbles,
EventCancelable::NotCancelable,
&window,
);
window
.task_manager()
.user_interaction_task_source()
.queue_event(
&self.element.upcast::<EventTarget>(),
atom!("select"),
EventBubbles::Bubbles,
EventCancelable::NotCancelable,
&window,
);
}
self.element

View file

@ -64,16 +64,7 @@ use crate::script_runtime::{
};
use crate::script_thread::{ImageCacheMsg, MainThreadScriptChan, MainThreadScriptMsg};
use crate::script_thread::{ScriptThread, SendableMainThreadScriptChan};
use crate::task::TaskCanceller;
use crate::task_source::dom_manipulation::DOMManipulationTaskSource;
use crate::task_source::file_reading::FileReadingTaskSource;
use crate::task_source::history_traversal::HistoryTraversalTaskSource;
use crate::task_source::media_element::MediaElementTaskSource;
use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::performance_timeline::PerformanceTimelineTaskSource;
use crate::task_source::remote_event::RemoteEventTaskSource;
use crate::task_source::user_interaction::UserInteractionTaskSource;
use crate::task_source::websocket::WebsocketTaskSource;
use crate::task_manager::TaskManager;
use crate::task_source::TaskSourceName;
use crate::timers::{IsInterval, TimerCallback};
use crate::webdriver_handlers::jsval_to_webdriver;
@ -127,7 +118,7 @@ use std::fs;
use std::io::{stderr, stdout, Write};
use std::mem;
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::atomic::Ordering;
use std::sync::{Arc, Mutex};
use style::error_reporting::ParseErrorReporter;
use style::media_queries;
@ -180,24 +171,7 @@ pub struct Window {
globalscope: GlobalScope,
#[ignore_malloc_size_of = "trait objects are hard"]
script_chan: MainThreadScriptChan,
#[ignore_malloc_size_of = "task sources are hard"]
dom_manipulation_task_source: DOMManipulationTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
media_element_task_source: MediaElementTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
user_interaction_task_source: UserInteractionTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
networking_task_source: NetworkingTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
history_traversal_task_source: HistoryTraversalTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
file_reading_task_source: FileReadingTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
performance_timeline_task_source: PerformanceTimelineTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
remote_event_task_source: RemoteEventTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
websocket_task_source: WebsocketTaskSource,
task_manager: TaskManager,
navigator: MutNullableDom<Navigator>,
#[ignore_malloc_size_of = "Arc"]
image_cache: Arc<ImageCache>,
@ -273,10 +247,6 @@ pub struct Window {
current_viewport: Cell<Rect<Au>>,
/// A map of flags to prevent events from a given task source from attempting to interact with this window.
#[ignore_malloc_size_of = "defined in std"]
ignore_further_async_events: DomRefCell<HashMap<TaskSourceName, Arc<AtomicBool>>>,
error_reporter: CSSErrorReporter,
/// A list of scroll offsets for each scrollable element.
@ -324,6 +294,10 @@ pub struct Window {
}
impl Window {
pub fn task_manager(&self) -> &TaskManager {
&self.task_manager
}
pub fn get_exists_mut_observer(&self) -> bool {
self.exists_mut_observer.get()
}
@ -343,7 +317,7 @@ impl Window {
}
fn ignore_all_events(&self) {
let mut ignore_flags = self.ignore_further_async_events.borrow_mut();
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)
@ -365,39 +339,6 @@ impl Window {
self.js_runtime.borrow().as_ref().unwrap().cx()
}
pub fn dom_manipulation_task_source(&self) -> DOMManipulationTaskSource {
self.dom_manipulation_task_source.clone()
}
pub fn media_element_task_source(&self) -> MediaElementTaskSource {
self.media_element_task_source.clone()
}
pub fn user_interaction_task_source(&self) -> UserInteractionTaskSource {
self.user_interaction_task_source.clone()
}
pub fn networking_task_source(&self) -> NetworkingTaskSource {
self.networking_task_source.clone()
}
pub fn file_reading_task_source(&self) -> TaskManagement<FileReadingTaskSource> {
let canceller = self.task_canceller(TaskSourceName::FileReading);
TaskManagement(self.file_reading_task_source.clone(), canceller)
}
pub fn performance_timeline_task_source(&self) -> PerformanceTimelineTaskSource {
self.performance_timeline_task_source.clone()
}
pub fn remote_event_task_source(&self) -> RemoteEventTaskSource {
self.remote_event_task_source.clone()
}
pub fn websocket_task_source(&self) -> WebsocketTaskSource {
self.websocket_task_source.clone()
}
pub fn main_thread_script_chan(&self) -> &Sender<MainThreadScriptMsg> {
&self.script_chan.0
}
@ -1231,14 +1172,6 @@ impl Window {
self.paint_worklet.or_init(|| self.new_paint_worklet())
}
pub fn task_canceller(&self, name: TaskSourceName) -> TaskCanceller {
let mut flags = self.ignore_further_async_events.borrow_mut();
let cancel_flag = flags.entry(name).or_insert(Default::default());
TaskCanceller {
cancelled: Some(cancel_flag.clone()),
}
}
pub fn get_navigation_start(&self) -> u64 {
self.navigation_start_precise.get()
}
@ -1249,10 +1182,10 @@ impl Window {
/// Cancels all the tasks associated with that window.
///
/// This sets the current `ignore_further_async_events` sentinel value to
/// 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.ignore_further_async_events.borrow_mut();
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)
@ -1266,7 +1199,7 @@ impl Window {
/// 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.ignore_further_async_events.borrow_mut();
let mut ignore_flags = self.task_manager.task_cancellers.borrow_mut();
let flag = ignore_flags
.entry(task_source_name)
.or_insert(Default::default());
@ -1827,7 +1760,8 @@ impl Window {
let _ = self.script_chan.send(CommonScriptMsg::Task(
ScriptThreadEventCategory::DomEvent,
Box::new(
self.task_canceller(TaskSourceName::DOMManipulation)
self.task_manager
.task_canceller(TaskSourceName::DOMManipulation)
.wrap_task(task),
),
self.pipeline_id(),
@ -2073,15 +2007,7 @@ impl Window {
pub fn new(
runtime: Rc<Runtime>,
script_chan: MainThreadScriptChan,
dom_manipulation_task_source: DOMManipulationTaskSource,
media_element_task_source: MediaElementTaskSource,
user_interaction_task_source: UserInteractionTaskSource,
networking_task_source: NetworkingTaskSource,
history_traversal_task_source: HistoryTraversalTaskSource,
file_reading_task_source: FileReadingTaskSource,
performance_timeline_task_source: PerformanceTimelineTaskSource,
remote_event_task_source: RemoteEventTaskSource,
websocket_task_source: WebsocketTaskSource,
task_manager: TaskManager,
image_cache_chan: Sender<ImageCacheMsg>,
image_cache: Arc<dyn ImageCache>,
resource_threads: ResourceThreads,
@ -2129,15 +2055,7 @@ impl Window {
microtask_queue,
),
script_chan,
dom_manipulation_task_source,
media_element_task_source,
user_interaction_task_source,
networking_task_source,
history_traversal_task_source,
file_reading_task_source,
performance_timeline_task_source,
remote_event_task_source,
websocket_task_source,
task_manager,
image_cache_chan,
image_cache,
navigator: Default::default(),
@ -2170,7 +2088,6 @@ impl Window {
devtools_marker_sender: Default::default(),
devtools_markers: Default::default(),
webdriver_script_chan: Default::default(),
ignore_further_async_events: Default::default(),
error_reporter,
scroll_offsets: Default::default(),
media_query_lists: DOMTracker::new(),
@ -2311,7 +2228,8 @@ impl Window {
let _ = self.script_chan.send(CommonScriptMsg::Task(
ScriptThreadEventCategory::DomEvent,
Box::new(
self.task_canceller(TaskSourceName::DOMManipulation)
self.task_manager
.task_canceller(TaskSourceName::DOMManipulation)
.wrap_task(task),
),
self.pipeline_id(),

View file

@ -10,7 +10,6 @@
use crate::dom::bindings::reflector::DomObject;
use crate::dom::node::{document_from_node, Node};
use crate::network_listener::{NetworkListener, PreInvoke};
use crate::task_source::TaskSourceName;
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
use net_traits::image_cache::{ImageCache, PendingImageId};
@ -57,13 +56,16 @@ pub fn fetch_image_for_layout(
}));
let document = document_from_node(node);
let window = document.window();
let (action_sender, action_receiver) = ipc::channel().unwrap();
let (task_source, canceller) = document
.window()
.task_manager()
.networking_task_source_with_canceller();
let listener = NetworkListener {
context: context,
task_source: window.networking_task_source(),
canceller: Some(window.task_canceller(TaskSourceName::Networking)),
context,
task_source,
canceller: Some(canceller),
};
ROUTER.add_route(
action_receiver.to_opaque(),

View file

@ -69,6 +69,7 @@ pub mod script_thread;
mod serviceworker_manager;
mod serviceworkerjob;
mod stylesheet_loader;
mod task_manager;
mod task_queue;
mod task_source;
pub mod test;

View file

@ -70,6 +70,7 @@ use crate::microtask::{Microtask, MicrotaskQueue};
use crate::script_runtime::{get_reports, new_rt_and_cx, Runtime, ScriptPort};
use crate::script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory};
use crate::serviceworkerjob::{Job, JobQueue};
use crate::task_manager::TaskManager;
use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
use crate::task_source::dom_manipulation::DOMManipulationTaskSource;
use crate::task_source::file_reading::FileReadingTaskSource;
@ -2583,20 +2584,23 @@ impl ScriptThread {
pipeline_id: incomplete.pipeline_id,
};
let task_manager = TaskManager::new(
self.dom_manipulation_task_source(incomplete.pipeline_id),
self.file_reading_task_source(incomplete.pipeline_id),
self.history_traversal_task_source(incomplete.pipeline_id),
self.media_element_task_source(incomplete.pipeline_id),
self.networking_task_source(incomplete.pipeline_id),
self.performance_timeline_task_source(incomplete.pipeline_id)
.clone(),
self.user_interaction_task_source(incomplete.pipeline_id),
self.remote_event_task_source(incomplete.pipeline_id),
self.websocket_task_source(incomplete.pipeline_id),
);
// Create the window and document objects.
let window = Window::new(
self.js_runtime.clone(),
MainThreadScriptChan(sender.clone()),
self.dom_manipulation_task_source(incomplete.pipeline_id),
self.media_element_task_source(incomplete.pipeline_id),
self.user_interaction_task_source(incomplete.pipeline_id),
self.networking_task_source(incomplete.pipeline_id),
self.history_traversal_task_source(incomplete.pipeline_id),
self.file_reading_task_source(incomplete.pipeline_id),
self.performance_timeline_task_source(incomplete.pipeline_id)
.clone(),
self.remote_event_task_source(incomplete.pipeline_id),
self.websocket_task_source(incomplete.pipeline_id),
task_manager,
self.image_cache_channel.clone(),
self.image_cache.clone(),
self.resource_threads.clone(),

View file

@ -13,7 +13,6 @@ use crate::dom::htmlelement::HTMLElement;
use crate::dom::htmllinkelement::{HTMLLinkElement, RequestGenerationId};
use crate::dom::node::{document_from_node, window_from_node};
use crate::network_listener::{NetworkListener, PreInvoke};
use crate::task_source::TaskSourceName;
use cssparser::SourceLocation;
use encoding_rs::UTF_8;
use ipc_channel::ipc;
@ -245,10 +244,14 @@ impl<'a> StylesheetLoader<'a> {
}));
let (action_sender, action_receiver) = ipc::channel().unwrap();
let (task_source, canceller) = document
.window()
.task_manager()
.networking_task_source_with_canceller();
let listener = NetworkListener {
context: context,
task_source: document.window().networking_task_source(),
canceller: Some(document.window().task_canceller(TaskSourceName::Networking)),
context,
task_source,
canceller: Some(canceller),
};
ROUTER.add_route(
action_receiver.to_opaque(),

View file

@ -0,0 +1,162 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::cell::DomRefCell;
use crate::task::TaskCanceller;
use crate::task_source::dom_manipulation::DOMManipulationTaskSource;
use crate::task_source::file_reading::FileReadingTaskSource;
use crate::task_source::history_traversal::HistoryTraversalTaskSource;
use crate::task_source::media_element::MediaElementTaskSource;
use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::performance_timeline::PerformanceTimelineTaskSource;
use crate::task_source::remote_event::RemoteEventTaskSource;
use crate::task_source::user_interaction::UserInteractionTaskSource;
use crate::task_source::websocket::WebsocketTaskSource;
use crate::task_source::TaskSourceName;
use std::collections::HashMap;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
macro_rules! task_source_functions {
($self:ident,$with_canceller:ident,$task_source:ident,$task_source_type:ident,$task_source_name:ident) => {
pub fn $with_canceller(&$self) -> ($task_source_type, TaskCanceller) {
($self.$task_source.clone(), $self.task_canceller(TaskSourceName::$task_source_name))
}
pub fn $task_source(&$self) -> $task_source_type {
$self.$task_source.clone()
}
}
}
#[derive(JSTraceable, MallocSizeOf)]
pub struct TaskManager {
#[ignore_malloc_size_of = "task sources are hard"]
pub task_cancellers: DomRefCell<HashMap<TaskSourceName, Arc<AtomicBool>>>,
#[ignore_malloc_size_of = "task sources are hard"]
dom_manipulation_task_source: DOMManipulationTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
file_reading_task_source: FileReadingTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
history_traversal_task_source: HistoryTraversalTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
media_element_task_source: MediaElementTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
networking_task_source: NetworkingTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
performance_timeline_task_source: PerformanceTimelineTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
user_interaction_task_source: UserInteractionTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
remote_event_task_source: RemoteEventTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
websocket_task_source: WebsocketTaskSource,
}
impl TaskManager {
pub fn new(
dom_manipulation_task_source: DOMManipulationTaskSource,
file_reading_task_source: FileReadingTaskSource,
history_traversal_task_source: HistoryTraversalTaskSource,
media_element_task_source: MediaElementTaskSource,
networking_task_source: NetworkingTaskSource,
performance_timeline_task_source: PerformanceTimelineTaskSource,
user_interaction_task_source: UserInteractionTaskSource,
remote_event_task_source: RemoteEventTaskSource,
websocket_task_source: WebsocketTaskSource,
) -> Self {
TaskManager {
dom_manipulation_task_source,
file_reading_task_source,
history_traversal_task_source,
media_element_task_source,
networking_task_source,
performance_timeline_task_source,
user_interaction_task_source,
remote_event_task_source,
websocket_task_source,
task_cancellers: Default::default(),
}
}
task_source_functions!(
self,
dom_manipulation_task_source_with_canceller,
dom_manipulation_task_source,
DOMManipulationTaskSource,
DOMManipulation
);
task_source_functions!(
self,
media_element_task_source_with_canceller,
media_element_task_source,
MediaElementTaskSource,
MediaElement
);
task_source_functions!(
self,
user_interaction_task_source_with_canceller,
user_interaction_task_source,
UserInteractionTaskSource,
UserInteraction
);
task_source_functions!(
self,
networking_task_source_with_canceller,
networking_task_source,
NetworkingTaskSource,
Networking
);
task_source_functions!(
self,
file_reading_task_source_with_canceller,
file_reading_task_source,
FileReadingTaskSource,
FileReading
);
task_source_functions!(
self,
history_traversal_task_source_with_canceller,
history_traversal_task_source,
HistoryTraversalTaskSource,
HistoryTraversal
);
task_source_functions!(
self,
performance_timeline_task_source_with_canceller,
performance_timeline_task_source,
PerformanceTimelineTaskSource,
PerformanceTimeline
);
task_source_functions!(
self,
remote_event_task_source_with_canceller,
remote_event_task_source,
RemoteEventTaskSource,
RemoteEvent
);
task_source_functions!(
self,
websocket_task_source_with_canceller,
websocket_task_source,
WebsocketTaskSource,
Websocket
);
pub fn task_canceller(&self, name: TaskSourceName) -> TaskCanceller {
let mut flags = self.task_cancellers.borrow_mut();
let cancel_flag = flags.entry(name).or_insert(Default::default());
TaskCanceller {
cancelled: Some(cancel_flag.clone()),
}
}
}

View file

@ -2,28 +2,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::script_runtime::{CommonScriptMsg, ScriptThreadEventCategory};
use crate::script_thread::MainThreadScriptMsg;
use crate::task::{TaskCanceller, TaskOnce};
use crate::task_source::{TaskSource, TaskSourceName};
use msg::constellation_msg::PipelineId;
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory};
use script_thread::MainThreadScriptMsg;
use servo_channel::Sender;
use task::{TaskCanceller, TaskOnce};
use task_source::{TaskSource, TaskSourceName};
#[derive(JSTraceable)]
#[derive(Clone, JSTraceable)]
pub struct HistoryTraversalTaskSource(pub Sender<MainThreadScriptMsg>, pub PipelineId);
impl ScriptChan for HistoryTraversalTaskSource {
fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
self.0
.send(MainThreadScriptMsg::Common(msg))
.map_err(|_| ())
}
fn clone(&self) -> Box<ScriptChan + Send> {
Box::new(HistoryTraversalTaskSource((&self.0).clone(), (&self.1).clone()))
}
}
impl TaskSource for HistoryTraversalTaskSource {
const NAME: TaskSourceName = TaskSourceName::HistoryTraversal;