mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Implement cancellable runnables.
Additionally, make image load events cancellable. Resolves #7731.
This commit is contained in:
parent
9fea6d2e46
commit
989e80036e
4 changed files with 62 additions and 8 deletions
|
@ -79,6 +79,7 @@ use std::mem;
|
|||
use std::ops::{Deref, DerefMut};
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::mpsc::{Receiver, Sender};
|
||||
use string_cache::{Atom, Namespace};
|
||||
use style::properties::PropertyDeclarationBlock;
|
||||
|
@ -246,7 +247,7 @@ impl<A: JSTraceable, B: JSTraceable> JSTraceable for (A, B) {
|
|||
}
|
||||
|
||||
|
||||
no_jsmanaged_fields!(bool, f32, f64, String, Url);
|
||||
no_jsmanaged_fields!(bool, f32, f64, String, Url, AtomicBool);
|
||||
no_jsmanaged_fields!(usize, u8, u16, u32, u64);
|
||||
no_jsmanaged_fields!(isize, i8, i16, i32, i64);
|
||||
no_jsmanaged_fields!(Sender<T>);
|
||||
|
|
|
@ -110,13 +110,16 @@ impl HTMLImageElement {
|
|||
let trusted_node = Trusted::new(window.get_cx(), self, window.script_chan());
|
||||
let (responder_sender, responder_receiver) = ipc::channel().unwrap();
|
||||
let script_chan = window.script_chan();
|
||||
let wrapper = window.get_runnable_wrapper();
|
||||
ROUTER.add_route(responder_receiver.to_opaque(), box move |message| {
|
||||
// Return the image via a message to the script task, which marks the element
|
||||
// as dirty and triggers a reflow.
|
||||
let image_response = message.to().unwrap();
|
||||
script_chan.send(CommonScriptMsg::RunnableMsg(UpdateReplacedElement,
|
||||
box ImageResponseHandlerRunnable::new(
|
||||
trusted_node.clone(), image_response))).unwrap();
|
||||
let runnable = ImageResponseHandlerRunnable::new(
|
||||
trusted_node.clone(), image_response);
|
||||
let runnable = wrapper.wrap_runnable(runnable);
|
||||
script_chan.send(CommonScriptMsg::RunnableMsg(
|
||||
UpdateReplacedElement, runnable)).unwrap();
|
||||
});
|
||||
|
||||
image_cache.request_image(img_url,
|
||||
|
|
|
@ -53,7 +53,7 @@ use num::traits::ToPrimitive;
|
|||
use page::Page;
|
||||
use profile_traits::mem;
|
||||
use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64};
|
||||
use script_task::{ScriptChan, ScriptPort, MainThreadScriptMsg};
|
||||
use script_task::{ScriptChan, ScriptPort, MainThreadScriptMsg, RunnableWrapper};
|
||||
use script_task::{SendableMainThreadScriptChan, MainThreadScriptChan, MainThreadTimerEventChan};
|
||||
use script_traits::{TimerEventChan, TimerEventId, TimerEventRequest, TimerSource};
|
||||
use selectors::parser::PseudoElement;
|
||||
|
@ -66,6 +66,7 @@ use std::ffi::CString;
|
|||
use std::io::{Write, stderr, stdout};
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::mpsc::TryRecvError::{Disconnected, Empty};
|
||||
use std::sync::mpsc::{Sender, channel};
|
||||
use string_cache::Atom;
|
||||
|
@ -209,7 +210,11 @@ pub struct Window {
|
|||
/// The current state of the window object
|
||||
current_state: Cell<WindowState>,
|
||||
|
||||
current_viewport: Cell<Rect<Au>>
|
||||
current_viewport: Cell<Rect<Au>>,
|
||||
|
||||
/// A flag to prevent async events from attempting to interact with this window.
|
||||
#[ignore_heap_size_of = "defined in std"]
|
||||
ignore_further_async_events: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
|
@ -219,6 +224,7 @@ impl Window {
|
|||
*self.js_runtime.borrow_for_script_deallocation() = None;
|
||||
self.browsing_context.set(None);
|
||||
self.current_state.set(WindowState::Zombie);
|
||||
self.ignore_further_async_events.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -781,6 +787,12 @@ impl<'a, T: Reflectable> ScriptHelpers for &'a T {
|
|||
}
|
||||
|
||||
impl Window {
|
||||
pub fn get_runnable_wrapper(&self) -> RunnableWrapper {
|
||||
RunnableWrapper {
|
||||
cancelled: self.ignore_further_async_events.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_js_runtime(&self) {
|
||||
self.Document().upcast::<Node>().teardown();
|
||||
|
||||
|
@ -798,6 +810,7 @@ impl Window {
|
|||
self.current_state.set(WindowState::Zombie);
|
||||
*self.js_runtime.borrow_mut() = None;
|
||||
self.browsing_context.set(None);
|
||||
self.ignore_further_async_events.store(true, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// https://drafts.csswg.org/cssom-view/#dom-window-scroll
|
||||
|
@ -1260,6 +1273,8 @@ impl Window {
|
|||
devtools_markers: DOMRefCell::new(HashSet::new()),
|
||||
devtools_wants_updates: Cell::new(false),
|
||||
webdriver_script_chan: DOMRefCell::new(None),
|
||||
|
||||
ignore_further_async_events: Arc::new(AtomicBool::new(false)),
|
||||
};
|
||||
|
||||
WindowBinding::Wrap(runtime.cx(), win)
|
||||
|
|
|
@ -95,6 +95,7 @@ use std::option::Option;
|
|||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
use std::result::Result;
|
||||
use std::sync::atomic::{Ordering, AtomicBool};
|
||||
use std::sync::mpsc::{Receiver, Select, Sender, channel};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use string_cache::Atom;
|
||||
|
@ -158,7 +159,38 @@ impl InProgressLoad {
|
|||
}
|
||||
}
|
||||
|
||||
/// Encapsulated state required to create cancellable runnables from non-script threads.
|
||||
pub struct RunnableWrapper {
|
||||
pub cancelled: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl RunnableWrapper {
|
||||
pub fn wrap_runnable<T: Runnable + Send + 'static>(&self, runnable: T) -> Box<Runnable + Send> {
|
||||
box CancellableRunnable {
|
||||
cancelled: self.cancelled.clone(),
|
||||
inner: box runnable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A runnable that can be discarded by toggling a shared flag.
|
||||
pub struct CancellableRunnable<T: Runnable + Send> {
|
||||
cancelled: Arc<AtomicBool>,
|
||||
inner: Box<T>,
|
||||
}
|
||||
|
||||
impl<T: Runnable + Send> Runnable for CancellableRunnable<T> {
|
||||
fn is_cancelled(&self) -> bool {
|
||||
self.cancelled.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
fn handler(self: Box<CancellableRunnable<T>>) {
|
||||
self.inner.handler()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Runnable {
|
||||
fn is_cancelled(&self) -> bool { false }
|
||||
fn handler(self: Box<Self>);
|
||||
}
|
||||
|
||||
|
@ -990,10 +1022,13 @@ impl ScriptTask {
|
|||
runnable.handler(self),
|
||||
MainThreadScriptMsg::DocumentLoadsComplete(id) =>
|
||||
self.handle_loads_complete(id),
|
||||
MainThreadScriptMsg::Common(CommonScriptMsg::RunnableMsg(_, runnable)) =>
|
||||
MainThreadScriptMsg::Common(CommonScriptMsg::RunnableMsg(_, runnable)) => {
|
||||
// The category of the runnable is ignored by the pattern, however
|
||||
// it is still respected by profiling (see categorize_msg).
|
||||
runnable.handler(),
|
||||
if !runnable.is_cancelled() {
|
||||
runnable.handler()
|
||||
}
|
||||
}
|
||||
MainThreadScriptMsg::Common(CommonScriptMsg::RefcountCleanup(addr)) =>
|
||||
LiveDOMReferences::cleanup(addr),
|
||||
MainThreadScriptMsg::Common(CommonScriptMsg::CollectReports(reports_chan)) =>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue