aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/abstractworkerglobalscope.rs21
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py13
-rw-r--r--components/script/dom/dedicatedworkerglobalscope.rs57
-rw-r--r--components/script/dom/dissimilaroriginwindow.rs4
-rw-r--r--components/script/dom/globalscope.rs103
-rw-r--r--components/script/dom/serviceworkerglobalscope.rs87
-rw-r--r--components/script/dom/webgl2renderingcontext.rs367
-rw-r--r--components/script/dom/webglrenderingcontext.rs8
-rw-r--r--components/script/dom/webidls/WebGL2RenderingContext.webidl8
-rw-r--r--components/script/dom/window.rs5
-rw-r--r--components/script/dom/workerglobalscope.rs12
-rw-r--r--components/script/dom/workletglobalscope.rs4
12 files changed, 539 insertions, 150 deletions
diff --git a/components/script/dom/abstractworkerglobalscope.rs b/components/script/dom/abstractworkerglobalscope.rs
index e8e41375b70..d5186f91845 100644
--- a/components/script/dom/abstractworkerglobalscope.rs
+++ b/components/script/dom/abstractworkerglobalscope.rs
@@ -81,32 +81,27 @@ impl ScriptPort for Receiver<DedicatedWorkerScriptMsg> {
}
pub trait WorkerEventLoopMethods {
- type TimerMsg: Send;
type WorkerMsg: QueuedTaskConversion + Send;
type Event;
- fn timer_event_port(&self) -> &Receiver<Self::TimerMsg>;
fn task_queue(&self) -> &TaskQueue<Self::WorkerMsg>;
fn handle_event(&self, event: Self::Event);
fn handle_worker_post_event(&self, worker: &TrustedWorkerAddress) -> Option<AutoWorkerReset>;
fn from_worker_msg(&self, msg: Self::WorkerMsg) -> Self::Event;
- fn from_timer_msg(&self, msg: Self::TimerMsg) -> Self::Event;
fn from_devtools_msg(&self, msg: DevtoolScriptControlMsg) -> Self::Event;
}
// https://html.spec.whatwg.org/multipage/#worker-event-loop
-pub fn run_worker_event_loop<T, TimerMsg, WorkerMsg, Event>(
+pub fn run_worker_event_loop<T, WorkerMsg, Event>(
worker_scope: &T,
worker: Option<&TrustedWorkerAddress>,
) where
- TimerMsg: Send,
WorkerMsg: QueuedTaskConversion + Send,
- T: WorkerEventLoopMethods<TimerMsg = TimerMsg, WorkerMsg = WorkerMsg, Event = Event>
+ T: WorkerEventLoopMethods<WorkerMsg = WorkerMsg, Event = Event>
+ DerivedFrom<WorkerGlobalScope>
+ DerivedFrom<GlobalScope>
+ DomObject,
{
let scope = worker_scope.upcast::<WorkerGlobalScope>();
- let timer_event_port = worker_scope.timer_event_port();
let devtools_port = match scope.from_devtools_sender() {
Some(_) => Some(scope.from_devtools_receiver()),
None => None,
@@ -117,7 +112,6 @@ pub fn run_worker_event_loop<T, TimerMsg, WorkerMsg, Event>(
task_queue.take_tasks(msg.unwrap());
worker_scope.from_worker_msg(task_queue.recv().unwrap())
},
- recv(timer_event_port) -> msg => worker_scope.from_timer_msg(msg.unwrap()),
recv(devtools_port.unwrap_or(&crossbeam_channel::never())) -> msg =>
worker_scope.from_devtools_msg(msg.unwrap()),
};
@@ -132,13 +126,10 @@ pub fn run_worker_event_loop<T, TimerMsg, WorkerMsg, Event>(
// Batch all events that are ready.
// The task queue will throttle non-priority tasks if necessary.
match task_queue.try_recv() {
- Err(_) => match timer_event_port.try_recv() {
- Err(_) => match devtools_port.map(|port| port.try_recv()) {
- None => {},
- Some(Err(_)) => break,
- Some(Ok(ev)) => sequential.push(worker_scope.from_devtools_msg(ev)),
- },
- Ok(ev) => sequential.push(worker_scope.from_timer_msg(ev)),
+ Err(_) => match devtools_port.map(|port| port.try_recv()) {
+ None => {},
+ Some(Err(_)) => break,
+ Some(Ok(ev)) => sequential.push(worker_scope.from_devtools_msg(ev)),
},
Ok(ev) => sequential.push(worker_scope.from_worker_msg(ev)),
}
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index fe3398417b2..39e8bfa275d 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -7408,7 +7408,16 @@ class CGIterableMethodGenerator(CGGeneric):
rooted!(in(*cx) let mut call_arg2 = UndefinedValue());
let mut call_args = vec![UndefinedValue(), UndefinedValue(), ObjectValue(*_obj)];
rooted!(in(*cx) let mut ignoredReturnVal = UndefinedValue());
- for i in 0..(*this).get_iterable_length() {
+
+ // This has to be a while loop since get_iterable_length() may change during
+ // the callback, and we need to avoid iterator invalidation.
+ //
+ // It is possible for this to loop infinitely, but that matches the spec
+ // and other browsers.
+ //
+ // https://heycam.github.io/webidl/#es-forEach
+ let mut i = 0;
+ while i < (*this).get_iterable_length() {
(*this).get_value_at_index(i).to_jsval(*cx, call_arg1.handle_mut());
(*this).get_key_at_index(i).to_jsval(*cx, call_arg2.handle_mut());
call_args[0] = call_arg1.handle().get();
@@ -7418,6 +7427,8 @@ class CGIterableMethodGenerator(CGGeneric):
ignoredReturnVal.handle_mut()) {
return false;
}
+
+ i += 1;
}
let result = ();
diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs
index 9b16b0348d7..2f339d1f8f8 100644
--- a/components/script/dom/dedicatedworkerglobalscope.rs
+++ b/components/script/dom/dedicatedworkerglobalscope.rs
@@ -37,7 +37,7 @@ use crate::task_source::TaskSourceName;
use crossbeam_channel::{unbounded, Receiver, Sender};
use devtools_traits::DevtoolScriptControlMsg;
use dom_struct::dom_struct;
-use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
+use ipc_channel::ipc::IpcReceiver;
use ipc_channel::router::ROUTER;
use js::jsapi::JS_AddInterruptCallback;
use js::jsapi::{Heap, JSContext, JSObject};
@@ -48,7 +48,7 @@ use net_traits::image_cache::ImageCache;
use net_traits::request::{CredentialsMode, Destination, ParserMetadata};
use net_traits::request::{Referrer, RequestBuilder, RequestMode};
use net_traits::IpcSend;
-use script_traits::{TimerEvent, TimerSource, WorkerGlobalScopeInit, WorkerScriptLoadOrigin};
+use script_traits::{WorkerGlobalScopeInit, WorkerScriptLoadOrigin};
use servo_rand::random;
use servo_url::ServoUrl;
use std::mem::replace;
@@ -93,7 +93,6 @@ pub enum DedicatedWorkerScriptMsg {
pub enum MixedMessage {
FromWorker(DedicatedWorkerScriptMsg),
- FromScheduler((TrustedWorkerAddress, TimerEvent)),
FromDevtools(DevtoolScriptControlMsg),
}
@@ -174,8 +173,6 @@ pub struct DedicatedWorkerGlobalScope {
task_queue: TaskQueue<DedicatedWorkerScriptMsg>,
#[ignore_malloc_size_of = "Defined in std"]
own_sender: Sender<DedicatedWorkerScriptMsg>,
- #[ignore_malloc_size_of = "Defined in std"]
- timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
#[ignore_malloc_size_of = "Trusted<T> has unclear ownership like Dom<T>"]
worker: DomRefCell<Option<TrustedWorkerAddress>>,
#[ignore_malloc_size_of = "Can't measure trait objects"]
@@ -186,14 +183,9 @@ pub struct DedicatedWorkerGlobalScope {
}
impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope {
- type TimerMsg = (TrustedWorkerAddress, TimerEvent);
type WorkerMsg = DedicatedWorkerScriptMsg;
type Event = MixedMessage;
- fn timer_event_port(&self) -> &Receiver<(TrustedWorkerAddress, TimerEvent)> {
- &self.timer_event_port
- }
-
fn task_queue(&self) -> &TaskQueue<DedicatedWorkerScriptMsg> {
&self.task_queue
}
@@ -211,10 +203,6 @@ impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope {
MixedMessage::FromWorker(msg)
}
- fn from_timer_msg(&self, msg: (TrustedWorkerAddress, TimerEvent)) -> MixedMessage {
- MixedMessage::FromScheduler(msg)
- }
-
fn from_devtools_msg(&self, msg: DevtoolScriptControlMsg) -> MixedMessage {
MixedMessage::FromDevtools(msg)
}
@@ -231,8 +219,6 @@ impl DedicatedWorkerGlobalScope {
parent_sender: Box<dyn ScriptChan + Send>,
own_sender: Sender<DedicatedWorkerScriptMsg>,
receiver: Receiver<DedicatedWorkerScriptMsg>,
- timer_event_chan: IpcSender<TimerEvent>,
- timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
closing: Arc<AtomicBool>,
image_cache: Arc<dyn ImageCache>,
) -> DedicatedWorkerGlobalScope {
@@ -244,12 +230,10 @@ impl DedicatedWorkerGlobalScope {
worker_url,
runtime,
from_devtools_receiver,
- timer_event_chan,
Some(closing),
),
task_queue: TaskQueue::new(receiver, own_sender.clone()),
own_sender: own_sender,
- timer_event_port: timer_event_port,
parent_sender: parent_sender,
worker: DomRefCell::new(None),
image_cache: image_cache,
@@ -267,8 +251,6 @@ impl DedicatedWorkerGlobalScope {
parent_sender: Box<dyn ScriptChan + Send>,
own_sender: Sender<DedicatedWorkerScriptMsg>,
receiver: Receiver<DedicatedWorkerScriptMsg>,
- timer_event_chan: IpcSender<TimerEvent>,
- timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
closing: Arc<AtomicBool>,
image_cache: Arc<dyn ImageCache>,
) -> DomRoot<DedicatedWorkerGlobalScope> {
@@ -283,8 +265,6 @@ impl DedicatedWorkerGlobalScope {
parent_sender,
own_sender,
receiver,
- timer_event_chan,
- timer_event_port,
closing,
image_cache,
));
@@ -347,10 +327,14 @@ impl DedicatedWorkerGlobalScope {
let runtime = unsafe {
if let Some(pipeline_id) = pipeline_id {
- new_child_runtime(
- parent,
- Some(NetworkingTaskSource(parent_sender.clone(), pipeline_id)),
- )
+ let task_source = NetworkingTaskSource(
+ Box::new(WorkerThreadWorkerChan {
+ sender: own_sender.clone(),
+ worker: worker.clone(),
+ }),
+ pipeline_id,
+ );
+ new_child_runtime(parent, Some(task_source))
} else {
new_child_runtime(parent, None)
}
@@ -362,17 +346,6 @@ impl DedicatedWorkerGlobalScope {
devtools_mpsc_chan,
);
- let (timer_tx, timer_rx) = unbounded();
- let (timer_ipc_chan, timer_ipc_port) = ipc::channel().unwrap();
- let worker_for_route = worker.clone();
- ROUTER.add_route(
- timer_ipc_port.to_opaque(),
- Box::new(move |message| {
- let event = message.to().unwrap();
- timer_tx.send((worker_for_route.clone(), event)).unwrap();
- }),
- );
-
let global = DedicatedWorkerGlobalScope::new(
init,
DOMString::from_string(worker_name),
@@ -383,8 +356,6 @@ impl DedicatedWorkerGlobalScope {
parent_sender.clone(),
own_sender,
receiver,
- timer_ipc_chan,
- timer_rx,
closing,
image_cache,
);
@@ -513,14 +484,6 @@ impl DedicatedWorkerGlobalScope {
},
_ => debug!("got an unusable devtools control message inside the worker!"),
},
- MixedMessage::FromScheduler((linked_worker, timer_event)) => match timer_event {
- TimerEvent(TimerSource::FromWorker, id) => {
- let _ar = AutoWorkerReset::new(self, linked_worker);
- let scope = self.upcast::<WorkerGlobalScope>();
- scope.handle_fire_timer(id);
- },
- TimerEvent(_, _) => panic!("A worker received a TimerEvent from a window."),
- },
MixedMessage::FromWorker(DedicatedWorkerScriptMsg::CommonWorker(
linked_worker,
msg,
diff --git a/components/script/dom/dissimilaroriginwindow.rs b/components/script/dom/dissimilaroriginwindow.rs
index ac596048717..ac866a90ff8 100644
--- a/components/script/dom/dissimilaroriginwindow.rs
+++ b/components/script/dom/dissimilaroriginwindow.rs
@@ -15,7 +15,6 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::windowproxy::WindowProxy;
use crate::script_runtime::JSContext;
use dom_struct::dom_struct;
-use ipc_channel::ipc;
use js::jsapi::{Heap, JSObject};
use js::jsval::{JSVal, UndefinedValue};
use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue};
@@ -48,8 +47,6 @@ impl DissimilarOriginWindow {
#[allow(unsafe_code)]
pub fn new(global_to_clone_from: &GlobalScope, window_proxy: &WindowProxy) -> DomRoot<Self> {
let cx = global_to_clone_from.get_cx();
- // Any timer events fired on this window are ignored.
- let (timer_event_chan, _) = ipc::channel().unwrap();
let win = Box::new(Self {
globalscope: GlobalScope::new_inherited(
PipelineId::new(),
@@ -59,7 +56,6 @@ impl DissimilarOriginWindow {
global_to_clone_from.script_to_constellation_chan().clone(),
global_to_clone_from.scheduler_chan().clone(),
global_to_clone_from.resource_threads().clone(),
- timer_event_chan,
global_to_clone_from.origin().clone(),
// FIXME(nox): The microtask queue is probably not important
// here, but this whole DOM interface is a hack anyway.
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index 1933d1e926e..4896c59e048 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -39,6 +39,7 @@ use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::performance_timeline::PerformanceTimelineTaskSource;
use crate::task_source::port_message::PortMessageQueue;
use crate::task_source::remote_event::RemoteEventTaskSource;
+use crate::task_source::timer::TimerTaskSource;
use crate::task_source::websocket::WebsocketTaskSource;
use crate::task_source::TaskSource;
use crate::task_source::TaskSourceName;
@@ -134,8 +135,13 @@ pub struct GlobalScope {
/// including resource_thread, filemanager_thread and storage_thread
resource_threads: ResourceThreads,
+ /// The mechanism by which time-outs and intervals are scheduled.
+ /// <https://html.spec.whatwg.org/multipage/#timers>
timers: OneshotTimers,
+ /// Have timers been initialized?
+ init_timers: Cell<bool>,
+
/// The origin of the globalscope
origin: MutableOrigin,
@@ -188,6 +194,13 @@ struct MessageListener {
context: Trusted<GlobalScope>,
}
+/// A wrapper between timer events coming in over IPC, and the event-loop.
+struct TimerListener {
+ canceller: TaskCanceller,
+ task_source: TimerTaskSource,
+ context: Trusted<GlobalScope>,
+}
+
/// Data representing a message-port managed by this global.
#[derive(JSTraceable, MallocSizeOf)]
pub enum ManagedMessagePort {
@@ -212,6 +225,34 @@ pub enum MessagePortState {
UnManaged,
}
+impl TimerListener {
+ /// Handle a timer-event coming-in over IPC,
+ /// by queuing the appropriate task on the relevant event-loop.
+ fn handle(&self, event: TimerEvent) {
+ let context = self.context.clone();
+ // Step 18, queue a task,
+ // https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
+ let _ = self.task_source.queue_with_canceller(
+ task!(timer_event: move || {
+ let global = context.root();
+ let TimerEvent(source, id) = event;
+ match source {
+ TimerSource::FromWorker => {
+ global.downcast::<WorkerGlobalScope>().expect("Window timer delivered to worker");
+ },
+ TimerSource::FromWindow(pipeline) => {
+ assert_eq!(pipeline, global.pipeline_id());
+ global.downcast::<Window>().expect("Worker timer delivered to window");
+ },
+ };
+ // Step 7, substeps run in a task.
+ global.fire_timer(id);
+ }),
+ &self.canceller,
+ );
+ }
+}
+
impl MessageListener {
/// A new message came in, handle it via a task enqueued on the event-loop.
/// A task is required, since we are using a trusted globalscope,
@@ -297,7 +338,6 @@ impl GlobalScope {
script_to_constellation_chan: ScriptToConstellationChan,
scheduler_chan: IpcSender<TimerSchedulerMsg>,
resource_threads: ResourceThreads,
- timer_event_chan: IpcSender<TimerEvent>,
origin: MutableOrigin,
microtask_queue: Rc<MicrotaskQueue>,
is_headless: bool,
@@ -318,7 +358,8 @@ impl GlobalScope {
scheduler_chan: scheduler_chan.clone(),
in_error_reporting_mode: Default::default(),
resource_threads,
- timers: OneshotTimers::new(timer_event_chan, scheduler_chan),
+ timers: OneshotTimers::new(scheduler_chan),
+ init_timers: Default::default(),
origin,
microtask_queue,
list_auto_close_worker: Default::default(),
@@ -349,6 +390,36 @@ impl GlobalScope {
false
}
+ /// Setup the IPC-to-event-loop glue for timers to schedule themselves.
+ fn setup_timers(&self) {
+ if self.init_timers.get() {
+ return;
+ }
+ self.init_timers.set(true);
+
+ let (timer_ipc_chan, timer_ipc_port) = ipc::channel().unwrap();
+ self.timers.setup_scheduling(timer_ipc_chan);
+
+ // Setup route from IPC to task-queue for the timer-task-source.
+ let context = Trusted::new(&*self);
+ let (task_source, canceller) = (
+ self.timer_task_source(),
+ self.task_canceller(TaskSourceName::Timer),
+ );
+ let timer_listener = TimerListener {
+ context,
+ task_source,
+ canceller,
+ };
+ ROUTER.add_route(
+ timer_ipc_port.to_opaque(),
+ Box::new(move |message| {
+ let event = message.to().unwrap();
+ timer_listener.handle(event);
+ }),
+ );
+ }
+
/// Complete the transfer of a message-port.
fn complete_port_transfer(&self, port_id: MessagePortId, tasks: VecDeque<PortMessageTask>) {
let should_start = if let MessagePortState::Managed(_id, message_ports) =
@@ -1063,6 +1134,18 @@ impl GlobalScope {
unreachable!();
}
+ /// `TaskSource` to send messages to the timer queue of
+ /// this global scope.
+ pub fn timer_task_source(&self) -> TimerTaskSource {
+ if let Some(window) = self.downcast::<Window>() {
+ return window.task_manager().timer_task_source();
+ }
+ if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
+ return worker.timer_task_source();
+ }
+ unreachable!();
+ }
+
/// `TaskSource` to send messages to the remote-event task source of
/// this global scope.
pub fn remote_event_task_source(&self) -> RemoteEventTaskSource {
@@ -1145,11 +1228,13 @@ impl GlobalScope {
)
}
+ /// <https://html.spec.whatwg.org/multipage/#timer-initialisation-steps>
pub fn schedule_callback(
&self,
callback: OneshotTimerCallback,
duration: MsDuration,
) -> OneshotTimerHandle {
+ self.setup_timers();
self.timers
.schedule_callback(callback, duration, self.timer_source())
}
@@ -1158,6 +1243,7 @@ impl GlobalScope {
self.timers.unschedule_callback(handle);
}
+ /// <https://html.spec.whatwg.org/multipage/#timer-initialisation-steps>
pub fn set_timeout_or_interval(
&self,
callback: TimerCallback,
@@ -1165,6 +1251,7 @@ impl GlobalScope {
timeout: i32,
is_interval: IsInterval,
) -> i32 {
+ self.setup_timers();
self.timers.set_timeout_or_interval(
self,
callback,
@@ -1176,27 +1263,27 @@ impl GlobalScope {
}
pub fn clear_timeout_or_interval(&self, handle: i32) {
- self.timers.clear_timeout_or_interval(self, handle)
+ self.timers.clear_timeout_or_interval(self, handle);
}
pub fn fire_timer(&self, handle: TimerEventId) {
- self.timers.fire_timer(handle, self)
+ self.timers.fire_timer(handle, self);
}
pub fn resume(&self) {
- self.timers.resume()
+ self.timers.resume();
}
pub fn suspend(&self) {
- self.timers.suspend()
+ self.timers.suspend();
}
pub fn slow_down_timers(&self) {
- self.timers.slow_down()
+ self.timers.slow_down();
}
pub fn speed_up_timers(&self) {
- self.timers.speed_up()
+ self.timers.speed_up();
}
fn timer_source(&self) -> TimerSource {
diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs
index cb72a4a25e4..2a3f4d7041a 100644
--- a/components/script/dom/serviceworkerglobalscope.rs
+++ b/components/script/dom/serviceworkerglobalscope.rs
@@ -28,24 +28,22 @@ use crate::script_runtime::{
};
use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
use crate::task_source::TaskSourceName;
-use crossbeam_channel::{unbounded, Receiver, Sender};
+use crossbeam_channel::{after, unbounded, Receiver, Sender};
use devtools_traits::DevtoolScriptControlMsg;
use dom_struct::dom_struct;
-use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
+use ipc_channel::ipc::{IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
use js::jsapi::{JSContext, JS_AddInterruptCallback};
use js::jsval::UndefinedValue;
use msg::constellation_msg::PipelineId;
use net_traits::request::{CredentialsMode, Destination, ParserMetadata, Referrer, RequestBuilder};
use net_traits::{CustomResponseMediator, IpcSend};
-use script_traits::{
- ScopeThings, ServiceWorkerMsg, TimerEvent, WorkerGlobalScopeInit, WorkerScriptLoadOrigin,
-};
+use script_traits::{ScopeThings, ServiceWorkerMsg, WorkerGlobalScopeInit, WorkerScriptLoadOrigin};
use servo_config::pref;
use servo_rand::random;
use servo_url::ServoUrl;
use std::thread;
-use std::time::Duration;
+use std::time::{Duration, Instant};
use style::thread_state::{self, ThreadState};
/// Messages used to control service worker event loop
@@ -118,7 +116,6 @@ impl QueuedTaskConversion for ServiceWorkerScriptMsg {
pub enum MixedMessage {
FromServiceWorker(ServiceWorkerScriptMsg),
FromDevtools(DevtoolScriptControlMsg),
- FromTimeoutThread(()),
}
#[derive(Clone, JSTraceable)]
@@ -147,26 +144,30 @@ unsafe_no_jsmanaged_fields!(TaskQueue<ServiceWorkerScriptMsg>);
#[dom_struct]
pub struct ServiceWorkerGlobalScope {
workerglobalscope: WorkerGlobalScope,
+
#[ignore_malloc_size_of = "Defined in std"]
task_queue: TaskQueue<ServiceWorkerScriptMsg>,
+
#[ignore_malloc_size_of = "Defined in std"]
own_sender: Sender<ServiceWorkerScriptMsg>,
+
+ /// A port on which a single "time-out" message can be received,
+ /// indicating the sw should stop running,
+ /// while still draining the task-queue
+ // and running all enqueued, and not cancelled, tasks.
#[ignore_malloc_size_of = "Defined in std"]
- timer_event_port: Receiver<()>,
+ time_out_port: Receiver<Instant>,
+
#[ignore_malloc_size_of = "Defined in std"]
swmanager_sender: IpcSender<ServiceWorkerMsg>,
+
scope_url: ServoUrl,
}
impl WorkerEventLoopMethods for ServiceWorkerGlobalScope {
- type TimerMsg = ();
type WorkerMsg = ServiceWorkerScriptMsg;
type Event = MixedMessage;
- fn timer_event_port(&self) -> &Receiver<()> {
- &self.timer_event_port
- }
-
fn task_queue(&self) -> &TaskQueue<ServiceWorkerScriptMsg> {
&self.task_queue
}
@@ -183,10 +184,6 @@ impl WorkerEventLoopMethods for ServiceWorkerGlobalScope {
MixedMessage::FromServiceWorker(msg)
}
- fn from_timer_msg(&self, msg: ()) -> MixedMessage {
- MixedMessage::FromTimeoutThread(msg)
- }
-
fn from_devtools_msg(&self, msg: DevtoolScriptControlMsg) -> MixedMessage {
MixedMessage::FromDevtools(msg)
}
@@ -200,8 +197,7 @@ impl ServiceWorkerGlobalScope {
runtime: Runtime,
own_sender: Sender<ServiceWorkerScriptMsg>,
receiver: Receiver<ServiceWorkerScriptMsg>,
- timer_event_chan: IpcSender<TimerEvent>,
- timer_event_port: Receiver<()>,
+ time_out_port: Receiver<Instant>,
swmanager_sender: IpcSender<ServiceWorkerMsg>,
scope_url: ServoUrl,
) -> ServiceWorkerGlobalScope {
@@ -213,12 +209,11 @@ impl ServiceWorkerGlobalScope {
worker_url,
runtime,
from_devtools_receiver,
- timer_event_chan,
None,
),
task_queue: TaskQueue::new(receiver, own_sender.clone()),
- timer_event_port: timer_event_port,
own_sender: own_sender,
+ time_out_port,
swmanager_sender: swmanager_sender,
scope_url: scope_url,
}
@@ -232,8 +227,7 @@ impl ServiceWorkerGlobalScope {
runtime: Runtime,
own_sender: Sender<ServiceWorkerScriptMsg>,
receiver: Receiver<ServiceWorkerScriptMsg>,
- timer_event_chan: IpcSender<TimerEvent>,
- timer_event_port: Receiver<()>,
+ time_out_port: Receiver<Instant>,
swmanager_sender: IpcSender<ServiceWorkerMsg>,
scope_url: ServoUrl,
) -> DomRoot<ServiceWorkerGlobalScope> {
@@ -245,8 +239,7 @@ impl ServiceWorkerGlobalScope {
runtime,
own_sender,
receiver,
- timer_event_chan,
- timer_event_port,
+ time_out_port,
swmanager_sender,
scope_url,
));
@@ -320,9 +313,12 @@ impl ServiceWorkerGlobalScope {
let (devtools_mpsc_chan, devtools_mpsc_port) = unbounded();
ROUTER
.route_ipc_receiver_to_crossbeam_sender(devtools_receiver, devtools_mpsc_chan);
- // TODO XXXcreativcoder use this timer_ipc_port, when we have a service worker instance here
- let (timer_ipc_chan, _timer_ipc_port) = ipc::channel().unwrap();
- let (timer_chan, timer_port) = unbounded();
+
+ // Service workers are time limited
+ // https://w3c.github.io/ServiceWorker/#service-worker-lifetime
+ let sw_lifetime_timeout = pref!(dom.serviceworker.timeout_seconds) as u64;
+ let time_out_port = after(Duration::new(sw_lifetime_timeout, 0));
+
let global = ServiceWorkerGlobalScope::new(
init,
url,
@@ -330,8 +326,7 @@ impl ServiceWorkerGlobalScope {
runtime,
own_sender,
receiver,
- timer_ipc_chan,
- timer_port,
+ time_out_port,
swmanager_sender,
scope_url,
);
@@ -343,15 +338,6 @@ impl ServiceWorkerGlobalScope {
}
scope.execute_script(DOMString::from(source));
- // Service workers are time limited
- thread::Builder::new()
- .name("SWTimeoutThread".to_owned())
- .spawn(move || {
- let sw_lifetime_timeout = pref!(dom.serviceworker.timeout_seconds) as u64;
- thread::sleep(Duration::new(sw_lifetime_timeout, 0));
- let _ = timer_chan.send(());
- })
- .expect("Thread spawning failed");
global.dispatch_activate();
let reporter_name = format!("service-worker-reporter-{}", random::<u64>());
@@ -364,8 +350,9 @@ impl ServiceWorkerGlobalScope {
// by inside settings until it is destroyed.
// The worker processing model remains on this step
// until the event loop is destroyed,
- // which happens after the closing flag is set to true.
- while !scope.is_closing() {
+ // which happens after the closing flag is set to true,
+ // or until the worker has run beyond its allocated time.
+ while !scope.is_closing() || !global.has_timed_out() {
run_worker_event_loop(&*global, None);
}
},
@@ -398,15 +385,21 @@ impl ServiceWorkerGlobalScope {
self.handle_script_event(msg);
true
},
- MixedMessage::FromTimeoutThread(_) => {
- let _ = self
- .swmanager_sender
- .send(ServiceWorkerMsg::Timeout(self.scope_url.clone()));
- false
- },
}
}
+ fn has_timed_out(&self) -> bool {
+ // Note: this should be included in the `select` inside `run_worker_event_loop`,
+ // otherwise a block on the select can prevent the timeout.
+ if self.time_out_port.try_recv().is_ok() {
+ let _ = self
+ .swmanager_sender
+ .send(ServiceWorkerMsg::Timeout(self.scope_url.clone()));
+ return true;
+ }
+ false
+ }
+
fn handle_script_event(&self, msg: ServiceWorkerScriptMsg) {
use self::ServiceWorkerScriptMsg::*;
diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs
index d9a3e81b46a..2c63b775bb1 100644
--- a/components/script/dom/webgl2renderingcontext.rs
+++ b/components/script/dom/webgl2renderingcontext.rs
@@ -25,7 +25,7 @@ use crate::dom::webglprogram::WebGLProgram;
use crate::dom::webglquery::WebGLQuery;
use crate::dom::webglrenderbuffer::WebGLRenderbuffer;
use crate::dom::webglrenderingcontext::{
- LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext,
+ LayoutCanvasWebGLRenderingContextHelpers, Size2DExt, WebGLRenderingContext,
};
use crate::dom::webglsampler::{WebGLSampler, WebGLSamplerValue};
use crate::dom::webglshader::WebGLShader;
@@ -42,13 +42,15 @@ use canvas_traits::webgl::{
webgl_channel, GLContextAttributes, WebGLCommand, WebGLResult, WebGLVersion,
};
use dom_struct::dom_struct;
-use euclid::default::Size2D;
+use euclid::default::{Point2D, Rect, Size2D};
use ipc_channel::ipc;
use js::jsapi::{JSObject, Type};
use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue, UInt32Value};
use js::rust::CustomAutoRooterGuard;
use js::typedarray::ArrayBufferView;
use script_layout_interface::HTMLCanvasDataSource;
+use std::cell::Cell;
+use std::cmp;
use std::ptr::NonNull;
#[dom_struct]
@@ -65,6 +67,9 @@ pub struct WebGL2RenderingContext {
bound_transform_feedback_buffer: MutNullableDom<WebGLBuffer>,
bound_uniform_buffer: MutNullableDom<WebGLBuffer>,
current_transform_feedback: MutNullableDom<WebGLTransformFeedback>,
+ texture_pack_row_length: Cell<usize>,
+ texture_pack_skip_pixels: Cell<usize>,
+ texture_pack_skip_rows: Cell<usize>,
}
fn typedarray_elem_size(typeid: Type) -> usize {
@@ -77,6 +82,17 @@ fn typedarray_elem_size(typeid: Type) -> usize {
}
}
+struct ReadPixelsAllowedFormats<'a> {
+ array_types: &'a [Type],
+ channels: usize,
+}
+
+struct ReadPixelsSizes {
+ row_stride: usize,
+ skipped_bytes: usize,
+ size: usize,
+}
+
impl WebGL2RenderingContext {
fn new_inherited(
window: &Window,
@@ -104,6 +120,9 @@ impl WebGL2RenderingContext {
bound_transform_feedback_buffer: MutNullableDom::new(None),
bound_uniform_buffer: MutNullableDom::new(None),
current_transform_feedback: MutNullableDom::new(None),
+ texture_pack_row_length: Cell::new(0),
+ texture_pack_skip_pixels: Cell::new(0),
+ texture_pack_skip_rows: Cell::new(0),
})
}
@@ -147,6 +166,213 @@ impl WebGL2RenderingContext {
slot.set(None);
}
}
+
+ fn calc_read_pixel_formats(
+ &self,
+ pixel_type: u32,
+ format: u32,
+ ) -> WebGLResult<ReadPixelsAllowedFormats> {
+ let array_types = match pixel_type {
+ constants::BYTE => &[Type::Int8][..],
+ constants::SHORT => &[Type::Int16][..],
+ constants::INT => &[Type::Int32][..],
+ constants::UNSIGNED_BYTE => &[Type::Uint8, Type::Uint8Clamped][..],
+ constants::UNSIGNED_SHORT |
+ constants::UNSIGNED_SHORT_4_4_4_4 |
+ constants::UNSIGNED_SHORT_5_5_5_1 |
+ constants::UNSIGNED_SHORT_5_6_5 => &[Type::Uint16][..],
+ constants::UNSIGNED_INT |
+ constants::UNSIGNED_INT_2_10_10_10_REV |
+ constants::UNSIGNED_INT_10F_11F_11F_REV |
+ constants::UNSIGNED_INT_5_9_9_9_REV => &[Type::Uint32][..],
+ constants::FLOAT => &[Type::Float32][..],
+ constants::HALF_FLOAT => &[Type::Uint16][..],
+ _ => return Err(InvalidEnum),
+ };
+ let channels = match format {
+ constants::ALPHA | constants::RED | constants::RED_INTEGER => 1,
+ constants::RG | constants::RG_INTEGER => 2,
+ constants::RGB | constants::RGB_INTEGER => 3,
+ constants::RGBA | constants::RGBA_INTEGER => 4,
+ _ => return Err(InvalidEnum),
+ };
+ Ok(ReadPixelsAllowedFormats {
+ array_types,
+ channels,
+ })
+ }
+
+ fn calc_read_pixel_sizes(
+ &self,
+ width: i32,
+ height: i32,
+ bytes_per_pixel: usize,
+ ) -> WebGLResult<ReadPixelsSizes> {
+ if width < 0 || height < 0 {
+ return Err(InvalidValue);
+ }
+
+ // See also https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.36
+ let pixels_per_row = if self.texture_pack_row_length.get() > 0 {
+ self.texture_pack_row_length.get()
+ } else {
+ width as usize
+ };
+ if self.texture_pack_skip_pixels.get() + width as usize > pixels_per_row {
+ return Err(InvalidOperation);
+ }
+
+ let bytes_per_row = pixels_per_row
+ .checked_mul(bytes_per_pixel)
+ .ok_or(InvalidOperation)?;
+ let row_padding_bytes = {
+ let pack_alignment = self.base.get_texture_packing_alignment() as usize;
+ match bytes_per_row % pack_alignment {
+ 0 => 0,
+ remainder => pack_alignment - remainder,
+ }
+ };
+ let row_stride = bytes_per_row + row_padding_bytes;
+ let size = if width == 0 || height == 0 {
+ 0
+ } else {
+ let full_row_bytes = row_stride
+ .checked_mul(height as usize - 1)
+ .ok_or(InvalidOperation)?;
+ let last_row_bytes = bytes_per_pixel
+ .checked_mul(width as usize)
+ .ok_or(InvalidOperation)?;
+ let result = full_row_bytes
+ .checked_add(last_row_bytes)
+ .ok_or(InvalidOperation)?;
+ result
+ };
+ let skipped_bytes = {
+ let skipped_row_bytes = self
+ .texture_pack_skip_rows
+ .get()
+ .checked_mul(row_stride)
+ .ok_or(InvalidOperation)?;
+ let skipped_pixel_bytes = self
+ .texture_pack_skip_pixels
+ .get()
+ .checked_mul(bytes_per_pixel)
+ .ok_or(InvalidOperation)?;
+ let result = skipped_row_bytes
+ .checked_add(skipped_pixel_bytes)
+ .ok_or(InvalidOperation)?;
+ result
+ };
+ Ok(ReadPixelsSizes {
+ row_stride,
+ skipped_bytes,
+ size,
+ })
+ }
+
+ #[allow(unsafe_code)]
+ fn read_pixels_into(
+ &self,
+ x: i32,
+ y: i32,
+ width: i32,
+ height: i32,
+ format: u32,
+ pixel_type: u32,
+ dst: &mut ArrayBufferView,
+ dst_elem_offset: u32,
+ ) {
+ handle_potential_webgl_error!(self.base, self.base.validate_framebuffer(), return);
+
+ if self.bound_pixel_pack_buffer.get().is_some() {
+ return self.base.webgl_error(InvalidOperation);
+ }
+
+ let dst_byte_offset = {
+ let dst_elem_size = typedarray_elem_size(dst.get_array_type());
+ dst_elem_offset as usize * dst_elem_size
+ };
+ if dst_byte_offset > dst.len() {
+ return self.base.webgl_error(InvalidValue);
+ }
+
+ let dst_array_type = dst.get_array_type();
+ let ReadPixelsAllowedFormats {
+ array_types: allowed_array_types,
+ channels,
+ } = match self.calc_read_pixel_formats(pixel_type, format) {
+ Ok(result) => result,
+ Err(error) => return self.base.webgl_error(error),
+ };
+ if !allowed_array_types.contains(&dst_array_type) {
+ return self.base.webgl_error(InvalidOperation);
+ }
+ if format != constants::RGBA || pixel_type != constants::UNSIGNED_BYTE {
+ return self.base.webgl_error(InvalidOperation);
+ }
+
+ let bytes_per_pixel = typedarray_elem_size(dst_array_type) * channels;
+ let ReadPixelsSizes {
+ row_stride,
+ skipped_bytes,
+ size,
+ } = match self.calc_read_pixel_sizes(width, height, bytes_per_pixel) {
+ Ok(result) => result,
+ Err(error) => return self.base.webgl_error(error),
+ };
+ let dst_end = dst_byte_offset + skipped_bytes + size;
+ let dst_pixels = unsafe { dst.as_mut_slice() };
+ if dst_pixels.len() < dst_end {
+ return self.base.webgl_error(InvalidOperation);
+ }
+
+ let dst_byte_offset = {
+ let margin_left = cmp::max(0, -x) as usize;
+ let margin_top = cmp::max(0, -y) as usize;
+ dst_byte_offset +
+ skipped_bytes +
+ margin_left * bytes_per_pixel +
+ margin_top * row_stride
+ };
+ let src_rect = {
+ let (fb_width, fb_height) = handle_potential_webgl_error!(
+ self.base,
+ self.base
+ .get_current_framebuffer_size()
+ .ok_or(InvalidOperation),
+ return
+ );
+ let src_origin = Point2D::new(x, y);
+ let src_size = Size2D::new(width as u32, height as u32);
+ let fb_size = Size2D::new(fb_width as u32, fb_height as u32);
+ match pixels::clip(src_origin, src_size.to_u64(), fb_size.to_u64()) {
+ Some(rect) => rect.to_u32(),
+ None => return,
+ }
+ };
+ let src_row_bytes = handle_potential_webgl_error!(
+ self.base,
+ src_rect
+ .size
+ .width
+ .checked_mul(bytes_per_pixel as u32)
+ .ok_or(InvalidOperation),
+ return
+ );
+
+ let (sender, receiver) = ipc::bytes_channel().unwrap();
+ self.base.send_command(WebGLCommand::ReadPixels(
+ src_rect, format, pixel_type, sender,
+ ));
+ let src = receiver.recv().unwrap();
+
+ for i in 0..src_rect.size.height as usize {
+ let src_start = i * src_row_bytes as usize;
+ let dst_start = dst_byte_offset + i * row_stride;
+ dst_pixels[dst_start..dst_start + src_row_bytes as usize]
+ .copy_from_slice(&src[src_start..src_start + src_row_bytes as usize]);
+ }
+ }
}
impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
@@ -936,9 +1162,18 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
self.base.LineWidth(width)
}
- /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.2
fn PixelStorei(&self, param_name: u32, param_value: i32) {
- self.base.PixelStorei(param_name, param_value)
+ if param_value < 0 {
+ return self.base.webgl_error(InvalidValue);
+ }
+
+ match param_name {
+ constants::PACK_ROW_LENGTH => self.texture_pack_row_length.set(param_value as _),
+ constants::PACK_SKIP_PIXELS => self.texture_pack_skip_pixels.set(param_value as _),
+ constants::PACK_SKIP_ROWS => self.texture_pack_skip_rows.set(param_value as _),
+ _ => self.base.PixelStorei(param_name, param_value),
+ }
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
@@ -955,10 +1190,128 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
height: i32,
format: u32,
pixel_type: u32,
- pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
+ mut pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
) {
- self.base
- .ReadPixels(x, y, width, height, format, pixel_type, pixels)
+ let pixels =
+ handle_potential_webgl_error!(self.base, pixels.as_mut().ok_or(InvalidValue), return);
+
+ self.read_pixels_into(x, y, width, height, format, pixel_type, pixels, 0)
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.10
+ fn ReadPixels_(
+ &self,
+ x: i32,
+ y: i32,
+ width: i32,
+ height: i32,
+ format: u32,
+ pixel_type: u32,
+ dst_byte_offset: i64,
+ ) {
+ handle_potential_webgl_error!(self.base, self.base.validate_framebuffer(), return);
+
+ let dst = match self.bound_pixel_pack_buffer.get() {
+ Some(buffer) => buffer,
+ None => return self.base.webgl_error(InvalidOperation),
+ };
+
+ if dst_byte_offset < 0 {
+ return self.base.webgl_error(InvalidValue);
+ }
+ let dst_byte_offset = dst_byte_offset as usize;
+ if dst_byte_offset > dst.capacity() {
+ return self.base.webgl_error(InvalidOperation);
+ }
+
+ let ReadPixelsAllowedFormats {
+ array_types: _,
+ channels: bytes_per_pixel,
+ } = match self.calc_read_pixel_formats(pixel_type, format) {
+ Ok(result) => result,
+ Err(error) => return self.base.webgl_error(error),
+ };
+ if format != constants::RGBA || pixel_type != constants::UNSIGNED_BYTE {
+ return self.base.webgl_error(InvalidOperation);
+ }
+
+ let ReadPixelsSizes {
+ row_stride: _,
+ skipped_bytes,
+ size,
+ } = match self.calc_read_pixel_sizes(width, height, bytes_per_pixel) {
+ Ok(result) => result,
+ Err(error) => return self.base.webgl_error(error),
+ };
+ let dst_end = dst_byte_offset + skipped_bytes + size;
+ if dst.capacity() < dst_end {
+ return self.base.webgl_error(InvalidOperation);
+ }
+
+ {
+ let (fb_width, fb_height) = handle_potential_webgl_error!(
+ self.base,
+ self.base
+ .get_current_framebuffer_size()
+ .ok_or(InvalidOperation),
+ return
+ );
+ let src_origin = Point2D::new(x, y);
+ let src_size = Size2D::new(width as u32, height as u32);
+ let fb_size = Size2D::new(fb_width as u32, fb_height as u32);
+ if pixels::clip(src_origin, src_size.to_u64(), fb_size.to_u64()).is_none() {
+ return;
+ }
+ }
+ let src_rect = Rect::new(Point2D::new(x, y), Size2D::new(width, height));
+
+ self.base.send_command(WebGLCommand::PixelStorei(
+ constants::PACK_ALIGNMENT,
+ self.base.get_texture_packing_alignment() as _,
+ ));
+ self.base.send_command(WebGLCommand::PixelStorei(
+ constants::PACK_ROW_LENGTH,
+ self.texture_pack_row_length.get() as _,
+ ));
+ self.base.send_command(WebGLCommand::PixelStorei(
+ constants::PACK_SKIP_ROWS,
+ self.texture_pack_skip_rows.get() as _,
+ ));
+ self.base.send_command(WebGLCommand::PixelStorei(
+ constants::PACK_SKIP_PIXELS,
+ self.texture_pack_skip_pixels.get() as _,
+ ));
+ self.base.send_command(WebGLCommand::ReadPixelsPP(
+ src_rect,
+ format,
+ pixel_type,
+ dst_byte_offset,
+ ));
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.10
+ #[allow(unsafe_code)]
+ fn ReadPixels__(
+ &self,
+ x: i32,
+ y: i32,
+ width: i32,
+ height: i32,
+ format: u32,
+ pixel_type: u32,
+ mut dst: CustomAutoRooterGuard<ArrayBufferView>,
+ dst_elem_offset: u32,
+ ) {
+ self.read_pixels_into(
+ x,
+ y,
+ width,
+ height,
+ format,
+ pixel_type,
+ &mut dst,
+ dst_elem_offset,
+ )
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 74fd8068a72..85930cd3529 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -380,7 +380,7 @@ impl WebGLRenderingContext {
//
// The WebGL spec mentions a couple more operations that trigger
// this: clear() and getParameter(IMPLEMENTATION_COLOR_READ_*).
- fn validate_framebuffer(&self) -> WebGLResult<()> {
+ pub fn validate_framebuffer(&self) -> WebGLResult<()> {
match self.bound_framebuffer.get() {
Some(fb) => match fb.check_status_for_rendering() {
CompleteForRendering::Complete => Ok(()),
@@ -481,7 +481,7 @@ impl WebGLRenderingContext {
self.send_command(WebGLCommand::VertexAttrib(indx, x, y, z, w));
}
- fn get_current_framebuffer_size(&self) -> Option<(i32, i32)> {
+ pub fn get_current_framebuffer_size(&self) -> Option<(i32, i32)> {
match self.bound_framebuffer.get() {
Some(fb) => return fb.size(),
@@ -490,6 +490,10 @@ impl WebGLRenderingContext {
}
}
+ pub fn get_texture_packing_alignment(&self) -> u8 {
+ self.texture_packing_alignment.get()
+ }
+
// LINEAR filtering may be forbidden when using WebGL extensions.
// https://www.khronos.org/registry/webgl/extensions/OES_texture_float_linear/
fn validate_filterable_texture(
diff --git a/components/script/dom/webidls/WebGL2RenderingContext.webidl b/components/script/dom/webidls/WebGL2RenderingContext.webidl
index 312c7b78211..71b5ab10034 100644
--- a/components/script/dom/webidls/WebGL2RenderingContext.webidl
+++ b/components/script/dom/webidls/WebGL2RenderingContext.webidl
@@ -497,10 +497,10 @@ interface mixin WebGL2RenderingContextBase
void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
/*[AllowShared]*/ ArrayBufferView? dstData);
// WebGL2:
- // void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
- // GLintptr offset);
- // void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
- // [AllowShared] ArrayBufferView dstData, GLuint dstOffset);
+ void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ GLintptr offset);
+ void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ /*[AllowShared]*/ ArrayBufferView dstData, GLuint dstOffset);
/* Multiple Render Targets */
// void drawBuffers(sequence<GLenum> buffers);
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 4ae94520f1f..ef8719ab8e6 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -106,8 +106,7 @@ use script_layout_interface::{PendingImageState, TrustedNodeAddress};
use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
use script_traits::{ConstellationControlMsg, DocumentState, HistoryEntryReplacement, LoadData};
use script_traits::{
- ScriptMsg, ScriptToConstellationChan, ScrollState, StructuredSerializedData, TimerEvent,
- TimerEventId,
+ ScriptMsg, ScriptToConstellationChan, ScrollState, StructuredSerializedData, TimerEventId,
};
use script_traits::{TimerSchedulerMsg, WindowSizeData, WindowSizeType};
use selectors::attr::CaseSensitivity;
@@ -2206,7 +2205,6 @@ impl Window {
constellation_chan: ScriptToConstellationChan,
control_chan: IpcSender<ConstellationControlMsg>,
scheduler_chan: IpcSender<TimerSchedulerMsg>,
- timer_event_chan: IpcSender<TimerEvent>,
layout_chan: Sender<Msg>,
pipelineid: PipelineId,
parent_info: Option<PipelineId>,
@@ -2250,7 +2248,6 @@ impl Window {
constellation_chan,
scheduler_chan,
resource_threads,
- timer_event_chan,
origin,
microtask_queue,
is_headless,
diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs
index 7e55cbfc046..e943b6b0ef4 100644
--- a/components/script/dom/workerglobalscope.rs
+++ b/components/script/dom/workerglobalscope.rs
@@ -34,6 +34,7 @@ use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::performance_timeline::PerformanceTimelineTaskSource;
use crate::task_source::port_message::PortMessageQueue;
use crate::task_source::remote_event::RemoteEventTaskSource;
+use crate::task_source::timer::TimerTaskSource;
use crate::task_source::websocket::WebsocketTaskSource;
use crate::timers::{IsInterval, TimerCallback};
use crossbeam_channel::Receiver;
@@ -50,7 +51,6 @@ use net_traits::request::{
};
use net_traits::IpcSend;
use script_traits::WorkerGlobalScopeInit;
-use script_traits::{TimerEvent, TimerEventId};
use servo_url::{MutableOrigin, ServoUrl};
use std::cell::Ref;
use std::default::Default;
@@ -120,7 +120,6 @@ impl WorkerGlobalScope {
worker_url: ServoUrl,
runtime: Runtime,
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
- timer_event_chan: IpcSender<TimerEvent>,
closing: Option<Arc<AtomicBool>>,
) -> Self {
// Install a pipeline-namespace in the current thread.
@@ -134,7 +133,6 @@ impl WorkerGlobalScope {
init.script_to_constellation_chan,
init.scheduler_chan,
init.resource_threads,
- timer_event_chan,
MutableOrigin::new(init.origin),
runtime.microtask_queue.clone(),
init.is_headless,
@@ -437,6 +435,10 @@ impl WorkerGlobalScope {
PortMessageQueue(self.script_chan(), self.pipeline_id())
}
+ pub fn timer_task_source(&self) -> TimerTaskSource {
+ TimerTaskSource(self.script_chan(), self.pipeline_id())
+ }
+
pub fn remote_event_task_source(&self) -> RemoteEventTaskSource {
RemoteEventTaskSource(self.script_chan(), self.pipeline_id())
}
@@ -466,10 +468,6 @@ impl WorkerGlobalScope {
}
}
- pub fn handle_fire_timer(&self, timer_id: TimerEventId) {
- self.upcast::<GlobalScope>().fire_timer(timer_id);
- }
-
pub fn close(&self) {
if let Some(ref closing) = self.closing {
closing.store(true, Ordering::SeqCst);
diff --git a/components/script/dom/workletglobalscope.rs b/components/script/dom/workletglobalscope.rs
index 90fa5bd0115..995014cfc1a 100644
--- a/components/script/dom/workletglobalscope.rs
+++ b/components/script/dom/workletglobalscope.rs
@@ -15,7 +15,6 @@ use crate::script_thread::MainThreadScriptMsg;
use crossbeam_channel::Sender;
use devtools_traits::ScriptToDevtoolsControlMsg;
use dom_struct::dom_struct;
-use ipc_channel::ipc;
use ipc_channel::ipc::IpcSender;
use js::jsval::UndefinedValue;
use js::rust::Runtime;
@@ -55,8 +54,6 @@ impl WorkletGlobalScope {
executor: WorkletExecutor,
init: &WorkletGlobalScopeInit,
) -> Self {
- // Any timer events fired on this global are ignored.
- let (timer_event_chan, _) = ipc::channel().unwrap();
let script_to_constellation_chan = ScriptToConstellationChan {
sender: init.to_constellation_sender.clone(),
pipeline_id,
@@ -70,7 +67,6 @@ impl WorkletGlobalScope {
script_to_constellation_chan,
init.scheduler_chan.clone(),
init.resource_threads.clone(),
- timer_event_chan,
MutableOrigin::new(ImmutableOrigin::new_opaque()),
Default::default(),
init.is_headless,