aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
authorAlex Touchet <alextouchet@outlook.com>2018-09-11 09:06:42 -0700
committerGitHub <noreply@github.com>2018-09-11 09:06:42 -0700
commit025b5550fc6f1fd74605b09973ffc606dae7432c (patch)
tree7dfb1026318b7a0135273b667d3f44e3ee8d737d /components/script/dom
parent9a7e1d17f0e054cb9f7eaafeee943a2ec5bc5e26 (diff)
parent049eb6887e29d8409b1dfe55bc31803f1c3220da (diff)
downloadservo-025b5550fc6f1fd74605b09973ffc606dae7432c.tar.gz
servo-025b5550fc6f1fd74605b09973ffc606dae7432c.zip
Merge branch 'master' into tidy
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/abstractworkerglobalscope.rs131
-rw-r--r--components/script/dom/audiobuffer.rs7
-rw-r--r--components/script/dom/audiobuffersourcenode.rs16
-rw-r--r--components/script/dom/audionode.rs19
-rw-r--r--components/script/dom/audioscheduledsourcenode.rs9
-rw-r--r--components/script/dom/baseaudiocontext.rs42
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py26
-rw-r--r--components/script/dom/bindings/error.rs8
-rw-r--r--components/script/dom/channelmergernode.rs83
-rw-r--r--components/script/dom/css.rs2
-rw-r--r--components/script/dom/cssmediarule.rs1
-rw-r--r--components/script/dom/csssupportsrule.rs1
-rw-r--r--components/script/dom/dedicatedworkerglobalscope.rs202
-rw-r--r--components/script/dom/document.rs18
-rw-r--r--components/script/dom/gainnode.rs29
-rw-r--r--components/script/dom/globalscope.rs13
-rw-r--r--components/script/dom/htmlimageelement.rs31
-rw-r--r--components/script/dom/htmllinkelement.rs1
-rw-r--r--components/script/dom/htmlstyleelement.rs1
-rw-r--r--components/script/dom/medialist.rs3
-rw-r--r--components/script/dom/mod.rs1
-rw-r--r--components/script/dom/offlineaudiocontext.rs4
-rw-r--r--components/script/dom/oscillatornode.rs16
-rw-r--r--components/script/dom/pannernode.rs33
-rw-r--r--components/script/dom/serviceworkerglobalscope.rs149
-rw-r--r--components/script/dom/vrdisplay.rs10
-rw-r--r--components/script/dom/webgl2renderingcontext.rs22
-rw-r--r--components/script/dom/webgl_extensions/ext/angleinstancedarrays.rs10
-rw-r--r--components/script/dom/webglbuffer.rs19
-rw-r--r--components/script/dom/webglrenderingcontext.rs791
-rw-r--r--components/script/dom/webglvertexarrayobjectoes.rs13
-rw-r--r--components/script/dom/webidls/BaseAudioContext.webidl8
-rw-r--r--components/script/dom/webidls/ChannelMergerNode.webidl16
-rw-r--r--components/script/dom/webidls/PannerNode.webidl2
-rw-r--r--components/script/dom/webidls/WebGL2RenderingContext.webidl5
-rw-r--r--components/script/dom/webidls/WebGLRenderingContext.webidl8
-rw-r--r--components/script/dom/websocket.rs27
-rw-r--r--components/script/dom/window.rs16
-rw-r--r--components/script/dom/worker.rs10
-rw-r--r--components/script/dom/workerglobalscope.rs9
-rw-r--r--components/script/dom/worklet.rs10
41 files changed, 1112 insertions, 710 deletions
diff --git a/components/script/dom/abstractworkerglobalscope.rs b/components/script/dom/abstractworkerglobalscope.rs
index f6d868765ed..45c594dbaee 100644
--- a/components/script/dom/abstractworkerglobalscope.rs
+++ b/components/script/dom/abstractworkerglobalscope.rs
@@ -2,25 +2,31 @@
* 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 devtools_traits::DevtoolScriptControlMsg;
use dom::abstractworker::WorkerScriptMsg;
-use dom::bindings::refcounted::Trusted;
+use dom::bindings::conversions::DerivedFrom;
use dom::bindings::reflector::DomObject;
-use dom::bindings::trace::JSTraceable;
+use dom::dedicatedworkerglobalscope::{AutoWorkerReset, DedicatedWorkerScriptMsg};
+use dom::globalscope::GlobalScope;
+use dom::worker::TrustedWorkerAddress;
+use dom::workerglobalscope::WorkerGlobalScope;
use script_runtime::{ScriptChan, CommonScriptMsg, ScriptPort};
-use std::sync::mpsc::{Receiver, Sender};
+use std::sync::mpsc::{Receiver, Select, Sender};
+use task_queue::{QueuedTaskConversion, TaskQueue};
/// A ScriptChan that can be cloned freely and will silently send a TrustedWorkerAddress with
/// common event loop messages. While this SendableWorkerScriptChan is alive, the associated
/// Worker object will remain alive.
#[derive(Clone, JSTraceable)]
-pub struct SendableWorkerScriptChan<T: DomObject> {
- pub sender: Sender<(Trusted<T>, CommonScriptMsg)>,
- pub worker: Trusted<T>,
+pub struct SendableWorkerScriptChan {
+ pub sender: Sender<DedicatedWorkerScriptMsg>,
+ pub worker: TrustedWorkerAddress,
}
-impl<T: JSTraceable + DomObject + 'static> ScriptChan for SendableWorkerScriptChan<T> {
+impl ScriptChan for SendableWorkerScriptChan {
fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
- self.sender.send((self.worker.clone(), msg)).map_err(|_| ())
+ let msg = DedicatedWorkerScriptMsg::CommonWorker(self.worker.clone(), WorkerScriptMsg::Common(msg));
+ self.sender.send(msg).map_err(|_| ())
}
fn clone(&self) -> Box<ScriptChan + Send> {
@@ -35,15 +41,16 @@ impl<T: JSTraceable + DomObject + 'static> ScriptChan for SendableWorkerScriptCh
/// worker event loop messages. While this SendableWorkerScriptChan is alive, the associated
/// Worker object will remain alive.
#[derive(Clone, JSTraceable)]
-pub struct WorkerThreadWorkerChan<T: DomObject> {
- pub sender: Sender<(Trusted<T>, WorkerScriptMsg)>,
- pub worker: Trusted<T>,
+pub struct WorkerThreadWorkerChan {
+ pub sender: Sender<DedicatedWorkerScriptMsg>,
+ pub worker: TrustedWorkerAddress,
}
-impl<T: JSTraceable + DomObject + 'static> ScriptChan for WorkerThreadWorkerChan<T> {
+impl ScriptChan for WorkerThreadWorkerChan {
fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
+ let msg = DedicatedWorkerScriptMsg::CommonWorker(self.worker.clone(), WorkerScriptMsg::Common(msg));
self.sender
- .send((self.worker.clone(), WorkerScriptMsg::Common(msg)))
+ .send(msg)
.map_err(|_| ())
}
@@ -55,12 +62,100 @@ impl<T: JSTraceable + DomObject + 'static> ScriptChan for WorkerThreadWorkerChan
}
}
-impl<T: DomObject> ScriptPort for Receiver<(Trusted<T>, WorkerScriptMsg)> {
+impl ScriptPort for Receiver<DedicatedWorkerScriptMsg> {
fn recv(&self) -> Result<CommonScriptMsg, ()> {
- match self.recv().map(|(_, msg)| msg) {
- Ok(WorkerScriptMsg::Common(script_msg)) => Ok(script_msg),
- Ok(WorkerScriptMsg::DOMMessage(_)) => panic!("unexpected worker event message!"),
- Err(_) => Err(()),
+ let common_msg = match self.recv() {
+ Ok(DedicatedWorkerScriptMsg::CommonWorker(_worker, common_msg)) => common_msg,
+ Err(_) => return Err(()),
+ Ok(DedicatedWorkerScriptMsg::WakeUp) => panic!("unexpected worker event message!")
+ };
+ match common_msg {
+ WorkerScriptMsg::Common(script_msg) => Ok(script_msg),
+ WorkerScriptMsg::DOMMessage(_) => panic!("unexpected worker event message!"),
}
}
}
+
+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;
+}
+
+#[allow(unsafe_code)]
+// https://html.spec.whatwg.org/multipage/#worker-event-loop
+pub fn run_worker_event_loop<T, TimerMsg, WorkerMsg, Event>(worker_scope: &T,
+ worker: Option<&TrustedWorkerAddress>)
+where
+ TimerMsg: Send,
+ WorkerMsg: QueuedTaskConversion + Send,
+ T: WorkerEventLoopMethods<TimerMsg = TimerMsg, 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 = scope.from_devtools_receiver();
+ let task_queue = worker_scope.task_queue();
+ let sel = Select::new();
+ let mut worker_handle = sel.handle(task_queue.select());
+ let mut timer_event_handle = sel.handle(timer_event_port);
+ let mut devtools_handle = sel.handle(devtools_port);
+ unsafe {
+ worker_handle.add();
+ timer_event_handle.add();
+ if scope.from_devtools_sender().is_some() {
+ devtools_handle.add();
+ }
+ }
+ let ret = sel.wait();
+ let event = {
+ if ret == worker_handle.id() {
+ task_queue.take_tasks();
+ worker_scope.from_worker_msg(task_queue.recv().unwrap())
+ } else if ret == timer_event_handle.id() {
+ worker_scope.from_timer_msg(timer_event_port.recv().unwrap())
+ } else if ret == devtools_handle.id() {
+ worker_scope.from_devtools_msg(devtools_port.recv().unwrap())
+ } else {
+ panic!("unexpected select result!")
+ }
+ };
+ let mut sequential = vec![];
+ sequential.push(event);
+ // https://html.spec.whatwg.org/multipage/#worker-event-loop
+ // Once the WorkerGlobalScope's closing flag is set to true,
+ // the event loop's task queues must discard any further tasks
+ // that would be added to them
+ // (tasks already on the queue are unaffected except where otherwise specified).
+ while !scope.is_closing() {
+ // 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.try_recv() {
+ Err(_) => break,
+ Ok(ev) => sequential.push(worker_scope.from_devtools_msg(ev)),
+ },
+ Ok(ev) => sequential.push(worker_scope.from_timer_msg(ev)),
+ },
+ Ok(ev) => sequential.push(worker_scope.from_worker_msg(ev)),
+ }
+ }
+ // Step 3
+ for event in sequential {
+ worker_scope.handle_event(event);
+ // Step 6
+ let _ar = match worker {
+ Some(worker) => worker_scope.handle_worker_post_event(worker),
+ None => None
+ };
+ worker_scope.upcast::<GlobalScope>().perform_a_microtask_checkpoint();
+ }
+}
diff --git a/components/script/dom/audiobuffer.rs b/components/script/dom/audiobuffer.rs
index 8cf3bb6648f..761bcde404b 100644
--- a/components/script/dom/audiobuffer.rs
+++ b/components/script/dom/audiobuffer.rs
@@ -64,7 +64,7 @@ impl AudioBuffer {
number_of_channels: u32,
length: u32,
sample_rate: f32,
- initial_data: Option<&[f32]>,
+ initial_data: Option<&[Vec<f32>]>,
) -> DomRoot<AudioBuffer> {
let buffer = AudioBuffer::new_inherited(number_of_channels, length, sample_rate);
let buffer = reflect_dom_object(Box::new(buffer), global, AudioBufferBinding::Wrap);
@@ -93,20 +93,19 @@ impl AudioBuffer {
}
#[allow(unsafe_code)]
- pub fn set_channels(&self, initial_data: Option<&[f32]>) {
+ pub fn set_channels(&self, initial_data: Option<&[Vec<f32>]>) {
let global = self.global();
let cx = global.get_cx();
let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
let chans = self.js_channels.borrow_mut();
for channel in 0..self.number_of_channels {
rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
- let offset = (channel * self.length) as usize;
match initial_data {
Some(data) => {
let _ = unsafe {
Float32Array::create(
cx,
- CreateWith::Slice(&data[offset..offset + (self.length as usize) - 1]),
+ CreateWith::Slice(data[channel as usize].as_slice()),
array.handle_mut(),
)
};
diff --git a/components/script/dom/audiobuffersourcenode.rs b/components/script/dom/audiobuffersourcenode.rs
index 79841e38e22..a3ddf4121a9 100644
--- a/components/script/dom/audiobuffersourcenode.rs
+++ b/components/script/dom/audiobuffersourcenode.rs
@@ -44,7 +44,7 @@ impl AudioBufferSourceNode {
window: &Window,
context: &BaseAudioContext,
options: &AudioBufferSourceOptions,
- ) -> AudioBufferSourceNode {
+ ) -> Fallible<AudioBufferSourceNode> {
let mut node_options = AudioNodeOptions::empty();
node_options.channelCount = Some(2);
node_options.channelCountMode = Some(ChannelCountMode::Max);
@@ -55,7 +55,7 @@ impl AudioBufferSourceNode {
&node_options,
0, /* inputs */
1, /* outputs */
- );
+ )?;
let node_id = source_node.node().node_id();
let playback_rate = AudioParam::new(
&window,
@@ -77,7 +77,7 @@ impl AudioBufferSourceNode {
f32::MIN,
f32::MAX,
);
- AudioBufferSourceNode {
+ Ok(AudioBufferSourceNode {
source_node,
buffer: Default::default(),
playback_rate: Dom::from_ref(&playback_rate),
@@ -85,7 +85,7 @@ impl AudioBufferSourceNode {
loop_enabled: Cell::new(options.loop_),
loop_start: Cell::new(*options.loopStart),
loop_end: Cell::new(*options.loopEnd),
- }
+ })
}
#[allow(unrooted_must_root)]
@@ -93,9 +93,9 @@ impl AudioBufferSourceNode {
window: &Window,
context: &BaseAudioContext,
options: &AudioBufferSourceOptions,
- ) -> DomRoot<AudioBufferSourceNode> {
- let node = AudioBufferSourceNode::new_inherited(window, context, options);
- reflect_dom_object(Box::new(node), window, AudioBufferSourceNodeBinding::Wrap)
+ ) -> Fallible<DomRoot<AudioBufferSourceNode>> {
+ let node = AudioBufferSourceNode::new_inherited(window, context, options)?;
+ Ok(reflect_dom_object(Box::new(node), window, AudioBufferSourceNodeBinding::Wrap))
}
pub fn Constructor(
@@ -103,7 +103,7 @@ impl AudioBufferSourceNode {
context: &BaseAudioContext,
options: &AudioBufferSourceOptions,
) -> Fallible<DomRoot<AudioBufferSourceNode>> {
- Ok(AudioBufferSourceNode::new(window, context, options))
+ AudioBufferSourceNode::new(window, context, options)
}
}
diff --git a/components/script/dom/audionode.rs b/components/script/dom/audionode.rs
index 4690f74245e..5a149dd814f 100644
--- a/components/script/dom/audionode.rs
+++ b/components/script/dom/audionode.rs
@@ -44,9 +44,14 @@ impl AudioNode {
options: &AudioNodeOptions,
number_of_inputs: u32,
number_of_outputs: u32,
- ) -> AudioNode {
+ ) -> Fallible<AudioNode> {
+ if let Some(c) = options.channelCount {
+ if c == 0 || c > MAX_CHANNEL_COUNT {
+ return Err(Error::NotSupported);
+ }
+ }
let node_id = context.audio_context_impl().create_node(node_type);
- AudioNode::new_inherited_for_id(node_id, context, options, number_of_inputs, number_of_outputs)
+ Ok(AudioNode::new_inherited_for_id(node_id, context, options, number_of_inputs, number_of_outputs))
}
pub fn new_inherited_for_id(
@@ -218,6 +223,11 @@ impl AudioNodeMethods for AudioNode {
return Err(Error::NotSupported)
}
}
+ EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelMergerNode) => {
+ if value != 1 {
+ return Err(Error::InvalidState)
+ }
+ }
// XXX We do not support any of the other AudioNodes with
// constraints yet. Add more cases here as we add support
// for new AudioNodes.
@@ -256,6 +266,11 @@ impl AudioNodeMethods for AudioNode {
return Err(Error::NotSupported)
}
}
+ EventTargetTypeId::AudioNode(AudioNodeTypeId::ChannelMergerNode) => {
+ if value != ChannelCountMode::Explicit {
+ return Err(Error::InvalidState)
+ }
+ }
// XXX We do not support any of the other AudioNodes with
// constraints yet. Add more cases here as we add support
// for new AudioNodes.
diff --git a/components/script/dom/audioscheduledsourcenode.rs b/components/script/dom/audioscheduledsourcenode.rs
index 03f1f952102..871a793f6ec 100644
--- a/components/script/dom/audioscheduledsourcenode.rs
+++ b/components/script/dom/audioscheduledsourcenode.rs
@@ -24,24 +24,25 @@ pub struct AudioScheduledSourceNode {
}
impl AudioScheduledSourceNode {
+ #[allow(unrooted_must_root)]
pub fn new_inherited(
node_type: AudioNodeInit,
context: &BaseAudioContext,
options: &AudioNodeOptions,
number_of_inputs: u32,
number_of_outputs: u32,
- ) -> AudioScheduledSourceNode {
- AudioScheduledSourceNode {
+ ) -> Fallible<AudioScheduledSourceNode> {
+ Ok(AudioScheduledSourceNode {
node: AudioNode::new_inherited(
node_type,
context,
options,
number_of_inputs,
number_of_outputs,
- ),
+ )?,
started: Cell::new(false),
stopped: Cell::new(false),
- }
+ })
}
pub fn node(&self) -> &AudioNode {
diff --git a/components/script/dom/baseaudiocontext.rs b/components/script/dom/baseaudiocontext.rs
index 9513a0b22d1..dbd821b64fe 100644
--- a/components/script/dom/baseaudiocontext.rs
+++ b/components/script/dom/baseaudiocontext.rs
@@ -16,6 +16,7 @@ use dom::bindings::codegen::Bindings::BaseAudioContextBinding::AudioContextState
use dom::bindings::codegen::Bindings::BaseAudioContextBinding::BaseAudioContextMethods;
use dom::bindings::codegen::Bindings::BaseAudioContextBinding::DecodeErrorCallback;
use dom::bindings::codegen::Bindings::BaseAudioContextBinding::DecodeSuccessCallback;
+use dom::bindings::codegen::Bindings::ChannelMergerNodeBinding::ChannelMergerOptions;
use dom::bindings::codegen::Bindings::GainNodeBinding::GainOptions;
use dom::bindings::codegen::Bindings::OscillatorNodeBinding::OscillatorOptions;
use dom::bindings::codegen::Bindings::PannerNodeBinding::PannerOptions;
@@ -25,6 +26,7 @@ use dom::bindings::num::Finite;
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::DomObject;
use dom::bindings::root::{DomRoot, MutNullableDom};
+use dom::channelmergernode::ChannelMergerNode;
use dom::domexception::{DOMErrorName, DOMException};
use dom::eventtarget::EventTarget;
use dom::gainnode::GainNode;
@@ -317,7 +319,7 @@ impl BaseAudioContextMethods for BaseAudioContext {
event_handler!(statechange, GetOnstatechange, SetOnstatechange);
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createoscillator
- fn CreateOscillator(&self) -> DomRoot<OscillatorNode> {
+ fn CreateOscillator(&self) -> Fallible<DomRoot<OscillatorNode>> {
OscillatorNode::new(
&self.global().as_window(),
&self,
@@ -326,7 +328,7 @@ impl BaseAudioContextMethods for BaseAudioContext {
}
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-creategain
- fn CreateGain(&self) -> DomRoot<GainNode> {
+ fn CreateGain(&self) -> Fallible<DomRoot<GainNode>> {
GainNode::new(&self.global().as_window(), &self, &GainOptions::empty())
}
@@ -335,6 +337,12 @@ impl BaseAudioContextMethods for BaseAudioContext {
PannerNode::new(&self.global().as_window(), &self, &PannerOptions::empty())
}
+ /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createchannelmerger
+ fn CreateChannelMerger(&self, count: u32) -> Fallible<DomRoot<ChannelMergerNode>> {
+ let mut opts = ChannelMergerOptions::empty();
+ opts.numberOfInputs = count;
+ ChannelMergerNode::new(&self.global().as_window(), &self, &opts)
+ }
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbuffer
fn CreateBuffer(
@@ -360,7 +368,7 @@ impl BaseAudioContextMethods for BaseAudioContext {
}
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbuffersource
- fn CreateBufferSource(&self) -> DomRoot<AudioBufferSourceNode> {
+ fn CreateBufferSource(&self) -> Fallible<DomRoot<AudioBufferSourceNode>> {
AudioBufferSourceNode::new(
&self.global().as_window(),
&self,
@@ -397,6 +405,7 @@ impl BaseAudioContextMethods for BaseAudioContext {
let audio_data = audio_data.to_vec();
let decoded_audio = Arc::new(Mutex::new(Vec::new()));
let decoded_audio_ = decoded_audio.clone();
+ let decoded_audio__ = decoded_audio.clone();
let this = Trusted::new(self);
let this_ = this.clone();
let task_source = window.dom_manipulation_task_source();
@@ -404,15 +413,30 @@ impl BaseAudioContextMethods for BaseAudioContext {
let canceller = window.task_canceller(TaskSourceName::DOMManipulation);
let canceller_ = window.task_canceller(TaskSourceName::DOMManipulation);
let callbacks = AudioDecoderCallbacks::new()
+ .ready(move |channel_count| {
+ decoded_audio
+ .lock()
+ .unwrap()
+ .resize(channel_count as usize, Vec::new());
+ })
+ .progress(move |buffer, channel| {
+ let mut decoded_audio = decoded_audio_.lock().unwrap();
+ decoded_audio[(channel - 1) as usize].extend_from_slice((*buffer).as_ref());
+ })
.eos(move || {
let _ = task_source.queue_with_canceller(
task!(audio_decode_eos: move || {
let this = this.root();
- let decoded_audio = decoded_audio.lock().unwrap();
+ let decoded_audio = decoded_audio__.lock().unwrap();
+ let length = if decoded_audio.len() >= 1 {
+ decoded_audio[0].len()
+ } else {
+ 0
+ };
let buffer = AudioBuffer::new(
&this.global().as_window(),
- 1, // XXX servo-media should provide this info
- decoded_audio.len() as u32,
+ decoded_audio.len() as u32 /* number of channels */,
+ length as u32,
this.sample_rate,
Some(decoded_audio.as_slice()));
let mut resolvers = this.decode_resolvers.borrow_mut();
@@ -443,12 +467,6 @@ impl BaseAudioContextMethods for BaseAudioContext {
&canceller_,
);
})
- .progress(move |buffer| {
- decoded_audio_
- .lock()
- .unwrap()
- .extend_from_slice((*buffer).as_ref());
- })
.build();
self.audio_context_impl
.decode_audio_data(audio_data, callbacks);
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index 449fda3b7ea..39409e7deaa 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -344,12 +344,17 @@ class CGMethodCall(CGThing):
distinguishingIndex = method.distinguishingIndexForArgCount(argCount)
- # We can't handle unions at the distinguishing index.
+ # We can't handle unions of non-object values at the distinguishing index.
for (returnType, args) in possibleSignatures:
- if args[distinguishingIndex].type.isUnion():
- raise TypeError("No support for unions as distinguishing "
- "arguments yet: %s",
- args[distinguishingIndex].location)
+ type = args[distinguishingIndex].type
+ if type.isUnion():
+ if type.nullable():
+ type = type.inner
+ for type in type.flatMemberTypes:
+ if not (type.isObject() or type.isNonCallbackInterface()):
+ raise TypeError("No support for unions with non-object variants "
+ "as distinguishing arguments yet: %s",
+ args[distinguishingIndex].location)
# Convert all our arguments up to the distinguishing index.
# Doesn't matter which of the possible signatures we use, since
@@ -388,6 +393,7 @@ class CGMethodCall(CGThing):
interfacesSigs = [
s for s in possibleSignatures
if (s[1][distinguishingIndex].type.isObject() or
+ s[1][distinguishingIndex].type.isUnion() or
s[1][distinguishingIndex].type.isNonCallbackInterface())]
# There might be more than one of these; we need to check
# which ones we unwrap to.
@@ -2366,7 +2372,6 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
'dom::bindings::conversions::ConversionBehavior',
'dom::bindings::conversions::StringificationBehavior',
'dom::bindings::conversions::root_from_handlevalue',
- 'dom::bindings::error::throw_not_in_union',
'std::ptr::NonNull',
'dom::bindings::mozmap::MozMap',
'dom::bindings::root::DomRoot',
@@ -4450,8 +4455,8 @@ class CGUnionConversionStruct(CGThing):
other.append(booleanConversion[0])
conversions.append(CGList(other, "\n\n"))
conversions.append(CGGeneric(
- "throw_not_in_union(cx, \"%s\");\n"
- "Err(())" % ", ".join(names)))
+ "Ok(ConversionResult::Failure(\"argument could not be converted to any of: %s\".into()))" % ", ".join(names)
+ ))
method = CGWrapper(
CGIndenter(CGList(conversions, "\n\n")),
pre="unsafe fn from_jsval(cx: *mut JSContext,\n"
@@ -4977,7 +4982,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod):
def __init__(self, descriptor):
args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'),
Argument('RawHandleId', 'id'),
- Argument('RawMutableHandle<PropertyDescriptor>', 'desc')]
+ Argument('RawMutableHandle<PropertyDescriptor>', 'mut desc')]
CGAbstractExternMethod.__init__(self, descriptor, "getOwnPropertyDescriptor",
"bool", args)
self.descriptor = descriptor
@@ -5050,7 +5055,6 @@ if %s {
else:
namedGet = ""
- # FIXME(#11868) Should assign to desc.obj, desc.get() is a copy.
return get + """\
rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
get_expando_object(proxy, expando.handle_mut());
@@ -5063,7 +5067,7 @@ if !expando.is_null() {
}
if !desc.obj.is_null() {
// Pretend the property lives on the wrapper.
- desc.get().obj = proxy.get();
+ desc.obj = proxy.get();
return true;
}
}
diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs
index c953df65c1d..7c68de0df18 100644
--- a/components/script/dom/bindings/error.rs
+++ b/components/script/dom/bindings/error.rs
@@ -255,14 +255,6 @@ pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool)
}
}
-/// Throw an exception to signal that a `JSVal` can not be converted to any of
-/// the types in an IDL union type.
-pub unsafe fn throw_not_in_union(cx: *mut JSContext, names: &'static str) {
- assert!(!JS_IsExceptionPending(cx));
- let error = format!("argument could not be converted to any of: {}", names);
- throw_type_error(cx, &error);
-}
-
/// Throw an exception to signal that a `JSObject` can not be converted to a
/// given DOM type.
pub unsafe fn throw_invalid_this(cx: *mut JSContext, proto_id: u16) {
diff --git a/components/script/dom/channelmergernode.rs b/components/script/dom/channelmergernode.rs
new file mode 100644
index 00000000000..d36c481a158
--- /dev/null
+++ b/components/script/dom/channelmergernode.rs
@@ -0,0 +1,83 @@
+/* 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 dom::audionode::{AudioNode, MAX_CHANNEL_COUNT};
+use dom::baseaudiocontext::BaseAudioContext;
+use dom::bindings::codegen::Bindings::AudioNodeBinding::{ChannelCountMode, ChannelInterpretation};
+use dom::bindings::codegen::Bindings::AudioNodeBinding::AudioNodeOptions;
+use dom::bindings::codegen::Bindings::ChannelMergerNodeBinding::{self, ChannelMergerOptions};
+use dom::bindings::error::{Error, Fallible};
+use dom::bindings::reflector::reflect_dom_object;
+use dom::bindings::root::DomRoot;
+use dom::window::Window;
+use dom_struct::dom_struct;
+use servo_media::audio::channel_node::ChannelNodeOptions;
+use servo_media::audio::node::AudioNodeInit;
+
+#[dom_struct]
+pub struct ChannelMergerNode {
+ node: AudioNode,
+}
+
+impl ChannelMergerNode {
+ #[allow(unrooted_must_root)]
+ pub fn new_inherited(
+ _: &Window,
+ context: &BaseAudioContext,
+ options: &ChannelMergerOptions,
+ ) -> Fallible<ChannelMergerNode> {
+ let mut node_options = AudioNodeOptions::empty();
+ let count = options.parent.channelCount.unwrap_or(1);
+ let mode = options.parent.channelCountMode.unwrap_or(ChannelCountMode::Explicit);
+ let interpretation = options.parent.channelInterpretation.unwrap_or(ChannelInterpretation::Speakers);
+
+ if count != 1 || mode != ChannelCountMode::Explicit {
+ return Err(Error::InvalidState)
+ }
+
+ if options.numberOfInputs < 1 || options.numberOfInputs > MAX_CHANNEL_COUNT {
+ return Err(Error::IndexSize)
+ }
+
+ node_options.channelCount = Some(count);
+ node_options.channelCountMode = Some(mode);
+ node_options.channelInterpretation = Some(interpretation);
+ let node = AudioNode::new_inherited(
+ AudioNodeInit::ChannelMergerNode(options.into()),
+ context,
+ &node_options,
+ options.numberOfInputs, // inputs
+ 1, // outputs
+ )?;
+ Ok(ChannelMergerNode {
+ node,
+ })
+ }
+
+ #[allow(unrooted_must_root)]
+ pub fn new(
+ window: &Window,
+ context: &BaseAudioContext,
+ options: &ChannelMergerOptions,
+ ) -> Fallible<DomRoot<ChannelMergerNode>> {
+ let node = ChannelMergerNode::new_inherited(window, context, options)?;
+ Ok(reflect_dom_object(Box::new(node), window, ChannelMergerNodeBinding::Wrap))
+ }
+
+ pub fn Constructor(
+ window: &Window,
+ context: &BaseAudioContext,
+ options: &ChannelMergerOptions,
+ ) -> Fallible<DomRoot<ChannelMergerNode>> {
+ ChannelMergerNode::new(window, context, options)
+ }
+}
+
+impl<'a> From<&'a ChannelMergerOptions> for ChannelNodeOptions {
+ fn from(options: &'a ChannelMergerOptions) -> Self {
+ Self {
+ channels: options.numberOfInputs as u8,
+ }
+ }
+}
diff --git a/components/script/dom/css.rs b/components/script/dom/css.rs
index d642b44a19f..7a42d6b6e68 100644
--- a/components/script/dom/css.rs
+++ b/components/script/dom/css.rs
@@ -44,6 +44,7 @@ impl CSS {
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
+ None,
);
decl.eval(&context)
}
@@ -61,6 +62,7 @@ impl CSS {
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
+ None,
);
cond.eval(&context)
} else {
diff --git a/components/script/dom/cssmediarule.rs b/components/script/dom/cssmediarule.rs
index 23f3c46a251..ccc803e4b42 100644
--- a/components/script/dom/cssmediarule.rs
+++ b/components/script/dom/cssmediarule.rs
@@ -81,6 +81,7 @@ impl CSSMediaRule {
ParsingMode::DEFAULT,
quirks_mode,
window.css_error_reporter(),
+ None,
);
let new_medialist = StyleMediaList::parse(&context, &mut input);
diff --git a/components/script/dom/csssupportsrule.rs b/components/script/dom/csssupportsrule.rs
index a96cd706b86..8b66fbe76cf 100644
--- a/components/script/dom/csssupportsrule.rs
+++ b/components/script/dom/csssupportsrule.rs
@@ -69,6 +69,7 @@ impl CSSSupportsRule {
ParsingMode::DEFAULT,
quirks_mode,
None,
+ None,
);
let enabled = cond.eval(&context);
let mut guard = self.cssconditionrule.shared_lock().write();
diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs
index 1c8c2316dde..c582177f42e 100644
--- a/components/script/dom/dedicatedworkerglobalscope.rs
+++ b/components/script/dom/dedicatedworkerglobalscope.rs
@@ -6,6 +6,7 @@ use devtools;
use devtools_traits::DevtoolScriptControlMsg;
use dom::abstractworker::{SimpleWorkerErrorHandler, WorkerScriptMsg};
use dom::abstractworkerglobalscope::{SendableWorkerScriptChan, WorkerThreadWorkerChan};
+use dom::abstractworkerglobalscope::{WorkerEventLoopMethods, run_worker_event_loop};
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding;
use dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding::DedicatedWorkerGlobalScopeMethods;
@@ -40,15 +41,17 @@ use servo_url::ServoUrl;
use std::mem::replace;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
-use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel};
+use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread;
use style::thread_state::{self, ThreadState};
+use task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
+use task_source::TaskSourceName;
/// Set the `worker` field of a related DedicatedWorkerGlobalScope object to a particular
/// value for the duration of this object's lifetime. This ensures that the related Worker
/// object only lives as long as necessary (ie. while events are being executed), while
/// providing a reference that can be cloned freely.
-struct AutoWorkerReset<'a> {
+pub struct AutoWorkerReset<'a> {
workerscope: &'a DedicatedWorkerGlobalScope,
old_worker: Option<TrustedWorkerAddress>,
}
@@ -70,20 +73,85 @@ impl<'a> Drop for AutoWorkerReset<'a> {
}
}
-enum MixedMessage {
- FromWorker((TrustedWorkerAddress, WorkerScriptMsg)),
+pub enum DedicatedWorkerScriptMsg {
+ /// Standard message from a worker.
+ CommonWorker(TrustedWorkerAddress, WorkerScriptMsg),
+ /// Wake-up call from the task queue.
+ WakeUp,
+}
+
+pub enum MixedMessage {
+ FromWorker(DedicatedWorkerScriptMsg),
FromScheduler((TrustedWorkerAddress, TimerEvent)),
FromDevtools(DevtoolScriptControlMsg)
}
+impl QueuedTaskConversion for DedicatedWorkerScriptMsg {
+ fn task_source_name(&self) -> Option<&TaskSourceName> {
+ let common_worker_msg = match self {
+ DedicatedWorkerScriptMsg::CommonWorker(_, common_worker_msg) => common_worker_msg,
+ _ => return None,
+ };
+ let script_msg = match common_worker_msg {
+ WorkerScriptMsg::Common(ref script_msg) => script_msg,
+ _ => return None,
+ };
+ match script_msg {
+ CommonScriptMsg::Task(_category, _boxed, _pipeline_id, source_name) => Some(&source_name),
+ _ => return None,
+ }
+ }
+
+ fn into_queued_task(self) -> Option<QueuedTask> {
+ let (worker, common_worker_msg) = match self {
+ DedicatedWorkerScriptMsg::CommonWorker(worker, common_worker_msg) => (worker, common_worker_msg),
+ _ => return None,
+ };
+ let script_msg = match common_worker_msg {
+ WorkerScriptMsg::Common(script_msg) => script_msg,
+ _ => return None,
+ };
+ let (category, boxed, pipeline_id, task_source) = match script_msg {
+ CommonScriptMsg::Task(category, boxed, pipeline_id, task_source) =>
+ (category, boxed, pipeline_id, task_source),
+ _ => return None,
+ };
+ Some((Some(worker), category, boxed, pipeline_id, task_source))
+ }
+
+ fn from_queued_task(queued_task: QueuedTask) -> Self {
+ let (worker, category, boxed, pipeline_id, task_source) = queued_task;
+ let script_msg = CommonScriptMsg::Task(
+ category,
+ boxed,
+ pipeline_id,
+ task_source
+ );
+ DedicatedWorkerScriptMsg::CommonWorker(worker.unwrap(), WorkerScriptMsg::Common(script_msg))
+ }
+
+ fn wake_up_msg() -> Self {
+ DedicatedWorkerScriptMsg::WakeUp
+ }
+
+ fn is_wake_up(&self) -> bool {
+ match self {
+ DedicatedWorkerScriptMsg::WakeUp => true,
+ _ => false,
+ }
+ }
+}
+
+unsafe_no_jsmanaged_fields!(TaskQueue<DedicatedWorkerScriptMsg>);
+
// https://html.spec.whatwg.org/multipage/#dedicatedworkerglobalscope
#[dom_struct]
pub struct DedicatedWorkerGlobalScope {
workerglobalscope: WorkerGlobalScope,
#[ignore_malloc_size_of = "Defined in std"]
- receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>,
+ task_queue: TaskQueue<DedicatedWorkerScriptMsg>,
#[ignore_malloc_size_of = "Defined in std"]
- own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
+ 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>"]
@@ -93,14 +161,49 @@ pub struct DedicatedWorkerGlobalScope {
parent_sender: Box<ScriptChan + Send>,
}
+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
+ }
+
+ fn handle_event(&self, event: MixedMessage) {
+ self.handle_mixed_message(event);
+ }
+
+ fn handle_worker_post_event(&self, worker: &TrustedWorkerAddress) -> Option<AutoWorkerReset> {
+ let ar = AutoWorkerReset::new(&self, worker.clone());
+ Some(ar)
+ }
+
+ fn from_worker_msg(&self, msg: DedicatedWorkerScriptMsg) -> MixedMessage {
+ 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)
+ }
+}
+
impl DedicatedWorkerGlobalScope {
fn new_inherited(init: WorkerGlobalScopeInit,
worker_url: ServoUrl,
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
runtime: Runtime,
parent_sender: Box<ScriptChan + Send>,
- own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
- receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>,
+ own_sender: Sender<DedicatedWorkerScriptMsg>,
+ receiver: Receiver<DedicatedWorkerScriptMsg>,
timer_event_chan: IpcSender<TimerEvent>,
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
closing: Arc<AtomicBool>)
@@ -112,7 +215,7 @@ impl DedicatedWorkerGlobalScope {
from_devtools_receiver,
timer_event_chan,
Some(closing)),
- receiver: receiver,
+ task_queue: TaskQueue::new(receiver, own_sender.clone()),
own_sender: own_sender,
timer_event_port: timer_event_port,
parent_sender: parent_sender,
@@ -126,8 +229,8 @@ impl DedicatedWorkerGlobalScope {
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
runtime: Runtime,
parent_sender: Box<ScriptChan + Send>,
- own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
- receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>,
+ own_sender: Sender<DedicatedWorkerScriptMsg>,
+ receiver: Receiver<DedicatedWorkerScriptMsg>,
timer_event_chan: IpcSender<TimerEvent>,
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
closing: Arc<AtomicBool>)
@@ -151,13 +254,14 @@ impl DedicatedWorkerGlobalScope {
}
#[allow(unsafe_code)]
+ // https://html.spec.whatwg.org/multipage/#run-a-worker
pub fn run_worker_scope(init: WorkerGlobalScopeInit,
worker_url: ServoUrl,
from_devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>,
worker: TrustedWorkerAddress,
parent_sender: Box<ScriptChan + Send>,
- own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
- receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>,
+ own_sender: Sender<DedicatedWorkerScriptMsg>,
+ receiver: Receiver<DedicatedWorkerScriptMsg>,
worker_load_origin: WorkerScriptLoadOrigin,
closing: Arc<AtomicBool>) {
let serialized_worker_url = worker_url.to_string();
@@ -196,7 +300,8 @@ impl DedicatedWorkerGlobalScope {
parent_sender.send(CommonScriptMsg::Task(
WorkerEvent,
Box::new(SimpleWorkerErrorHandler::new(worker)),
- pipeline_id
+ pipeline_id,
+ TaskSourceName::DOMManipulation,
)).unwrap();
return;
}
@@ -242,17 +347,11 @@ impl DedicatedWorkerGlobalScope {
let reporter_name = format!("dedicated-worker-reporter-{}", random::<u64>());
scope.upcast::<GlobalScope>().mem_profiler_chan().run_with_memory_reporting(|| {
- // https://html.spec.whatwg.org/multipage/#event-loop-processing-model
- // Step 1
- while let Ok(event) = global.receive_event() {
- if scope.is_closing() {
- break;
- }
- // Step 3
- global.handle_event(event);
- // Step 6
- let _ar = AutoWorkerReset::new(&global, worker.clone());
- global.upcast::<GlobalScope>().perform_a_microtask_checkpoint();
+ // Step 29, Run the responsible event loop specified 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() {
+ run_worker_event_loop(&*global, Some(&worker));
}
}, reporter_name, parent_sender, CommonScriptMsg::CollectReports);
}).expect("Thread spawning failed");
@@ -274,36 +373,6 @@ impl DedicatedWorkerGlobalScope {
(chan, Box::new(rx))
}
- #[allow(unsafe_code)]
- fn receive_event(&self) -> Result<MixedMessage, RecvError> {
- let scope = self.upcast::<WorkerGlobalScope>();
- let worker_port = &self.receiver;
- let timer_event_port = &self.timer_event_port;
- let devtools_port = scope.from_devtools_receiver();
-
- let sel = Select::new();
- let mut worker_handle = sel.handle(worker_port);
- let mut timer_event_handle = sel.handle(timer_event_port);
- let mut devtools_handle = sel.handle(devtools_port);
- unsafe {
- worker_handle.add();
- timer_event_handle.add();
- if scope.from_devtools_sender().is_some() {
- devtools_handle.add();
- }
- }
- let ret = sel.wait();
- if ret == worker_handle.id() {
- Ok(MixedMessage::FromWorker(worker_port.recv()?))
- } else if ret == timer_event_handle.id() {
- Ok(MixedMessage::FromScheduler(timer_event_port.recv()?))
- } else if ret == devtools_handle.id() {
- Ok(MixedMessage::FromDevtools(devtools_port.recv()?))
- } else {
- panic!("unexpected select result!")
- }
- }
-
fn handle_script_event(&self, msg: WorkerScriptMsg) {
match msg {
WorkerScriptMsg::DOMMessage(data) => {
@@ -321,8 +390,8 @@ impl DedicatedWorkerGlobalScope {
}
}
- fn handle_event(&self, event: MixedMessage) {
- match event {
+ fn handle_mixed_message(&self, msg: MixedMessage) {
+ match msg {
MixedMessage::FromDevtools(msg) => {
match msg {
DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) =>
@@ -346,10 +415,11 @@ impl DedicatedWorkerGlobalScope {
}
}
}
- MixedMessage::FromWorker((linked_worker, msg)) => {
+ MixedMessage::FromWorker(DedicatedWorkerScriptMsg::CommonWorker(linked_worker, msg)) => {
let _ar = AutoWorkerReset::new(self, linked_worker);
self.handle_script_event(msg);
}
+ MixedMessage::FromWorker(DedicatedWorkerScriptMsg::WakeUp) => {},
}
}
@@ -382,8 +452,12 @@ impl DedicatedWorkerGlobalScope {
global.report_an_error(error_info, HandleValue::null());
}
}));
- // TODO: Should use the DOM manipulation task source.
- self.parent_sender.send(CommonScriptMsg::Task(WorkerEvent, task, Some(pipeline_id))).unwrap();
+ self.parent_sender.send(CommonScriptMsg::Task(
+ WorkerEvent,
+ task,
+ Some(pipeline_id),
+ TaskSourceName::DOMManipulation,
+ )).unwrap();
}
}
@@ -408,7 +482,13 @@ impl DedicatedWorkerGlobalScopeMethods for DedicatedWorkerGlobalScope {
let task = Box::new(task!(post_worker_message: move || {
Worker::handle_message(worker, data);
}));
- self.parent_sender.send(CommonScriptMsg::Task(WorkerEvent, task, Some(pipeline_id))).unwrap();
+ // TODO: Change this task source to a new `unshipped-port-message-queue` task source
+ self.parent_sender.send(CommonScriptMsg::Task(
+ WorkerEvent,
+ task,
+ Some(pipeline_id),
+ TaskSourceName::DOMManipulation,
+ )).unwrap();
Ok(())
}
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 5394089d220..cc1a82d04ef 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -2837,7 +2837,14 @@ impl Document {
let trusted_pending = Trusted::new(pending);
let trusted_promise = TrustedPromise::new(promise.clone());
let handler = ElementPerformFullscreenEnter::new(trusted_pending, trusted_promise, error);
- let script_msg = CommonScriptMsg::Task(ScriptThreadEventCategory::EnterFullscreen, handler, pipeline_id);
+ // NOTE: This steps should be running in parallel
+ // https://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen
+ let script_msg = CommonScriptMsg::Task(
+ ScriptThreadEventCategory::EnterFullscreen,
+ handler,
+ pipeline_id,
+ TaskSourceName::DOMManipulation,
+ );
let msg = MainThreadScriptMsg::Common(script_msg);
window.main_thread_script_chan().send(msg).unwrap();
@@ -2870,7 +2877,14 @@ impl Document {
let trusted_promise = TrustedPromise::new(promise.clone());
let handler = ElementPerformFullscreenExit::new(trusted_element, trusted_promise);
let pipeline_id = Some(global.pipeline_id());
- let script_msg = CommonScriptMsg::Task(ScriptThreadEventCategory::ExitFullscreen, handler, pipeline_id);
+ // NOTE: This steps should be running in parallel
+ // https://fullscreen.spec.whatwg.org/#exit-fullscreen
+ let script_msg = CommonScriptMsg::Task(
+ ScriptThreadEventCategory::ExitFullscreen,
+ handler,
+ pipeline_id,
+ TaskSourceName::DOMManipulation,
+ );
let msg = MainThreadScriptMsg::Common(script_msg);
window.main_thread_script_chan().send(msg).unwrap();
diff --git a/components/script/dom/gainnode.rs b/components/script/dom/gainnode.rs
index 5cdbd8a89c9..a48cdc7c86b 100644
--- a/components/script/dom/gainnode.rs
+++ b/components/script/dom/gainnode.rs
@@ -30,19 +30,22 @@ impl GainNode {
pub fn new_inherited(
window: &Window,
context: &BaseAudioContext,
- gain_options: &GainOptions,
- ) -> GainNode {
+ options: &GainOptions,
+ ) -> Fallible<GainNode> {
let mut node_options = AudioNodeOptions::empty();
- node_options.channelCount = Some(2);
- node_options.channelCountMode = Some(ChannelCountMode::Max);
- node_options.channelInterpretation = Some(ChannelInterpretation::Speakers);
+ let count = options.parent.channelCount.unwrap_or(2);
+ let mode = options.parent.channelCountMode.unwrap_or(ChannelCountMode::Max);
+ let interpretation = options.parent.channelInterpretation.unwrap_or(ChannelInterpretation::Speakers);
+ node_options.channelCount = Some(count);
+ node_options.channelCountMode = Some(mode);
+ node_options.channelInterpretation = Some(interpretation);
let node = AudioNode::new_inherited(
- AudioNodeInit::GainNode(gain_options.into()),
+ AudioNodeInit::GainNode(options.into()),
context,
&node_options,
1, // inputs
1, // outputs
- );
+ )?;
let gain = AudioParam::new(
window,
context,
@@ -53,10 +56,10 @@ impl GainNode {
f32::MIN, // min value
f32::MAX, // max value
);
- GainNode {
+ Ok(GainNode {
node,
gain: Dom::from_ref(&gain),
- }
+ })
}
#[allow(unrooted_must_root)]
@@ -64,9 +67,9 @@ impl GainNode {
window: &Window,
context: &BaseAudioContext,
options: &GainOptions,
- ) -> DomRoot<GainNode> {
- let node = GainNode::new_inherited(window, context, options);
- reflect_dom_object(Box::new(node), window, GainNodeBinding::Wrap)
+ ) -> Fallible<DomRoot<GainNode>> {
+ let node = GainNode::new_inherited(window, context, options)?;
+ Ok(reflect_dom_object(Box::new(node), window, GainNodeBinding::Wrap))
}
pub fn Constructor(
@@ -74,7 +77,7 @@ impl GainNode {
context: &BaseAudioContext,
options: &GainOptions,
) -> Fallible<DomRoot<GainNode>> {
- Ok(GainNode::new(window, context, options))
+ GainNode::new(window, context, options)
}
}
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index 596530058ec..b2429948874 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -59,6 +59,7 @@ use task_source::file_reading::FileReadingTaskSource;
use task_source::networking::NetworkingTaskSource;
use task_source::performance_timeline::PerformanceTimelineTaskSource;
use task_source::remote_event::RemoteEventTaskSource;
+use task_source::websocket::WebsocketTaskSource;
use time::{Timespec, get_time};
use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle};
use timers::{OneshotTimers, TimerCallback};
@@ -430,6 +431,18 @@ impl GlobalScope {
unreachable!();
}
+ /// `ScriptChan` to send messages to the websocket task source of
+ /// this global scope.
+ pub fn websocket_task_source(&self) -> WebsocketTaskSource {
+ if let Some(window) = self.downcast::<Window>() {
+ return window.websocket_task_source();
+ }
+ if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
+ return worker.websocket_task_source();
+ }
+ unreachable!();
+ }
+
/// Evaluate JS code on this global scope.
pub fn evaluate_js_on_global_with_result(
&self, code: &str, rval: MutableHandleValue) -> bool {
diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs
index 7261f34b8ca..3aaa7c579cb 100644
--- a/components/script/dom/htmlimageelement.rs
+++ b/components/script/dom/htmlimageelement.rs
@@ -538,12 +538,17 @@ impl HTMLImageElement {
/// https://html.spec.whatwg.org/multipage/#matches-the-environment
fn matches_environment(&self, media_query: String) -> bool {
let document = document_from_node(self);
- let device = document.device();
- if !device.is_some() {
- return false;
- }
+ let device = match document.device() {
+ Some(device) => device,
+ None => return false,
+ };
let quirks_mode = document.quirks_mode();
let document_url = &document.url();
+ // FIXME(emilio): This should do the same that we do for other media
+ // lists regarding the rule type and such, though it doesn't really
+ // matter right now...
+ //
+ // Also, ParsingMode::all() is wrong, and should be DEFAULT.
let context = ParserContext::new(
Origin::Author,
document_url,
@@ -551,11 +556,12 @@ impl HTMLImageElement {
ParsingMode::all(),
quirks_mode,
None,
+ None,
);
let mut parserInput = ParserInput::new(&media_query);
let mut parser = Parser::new(&mut parserInput);
let media_list = MediaList::parse(&context, &mut parser);
- media_list.evaluate(&device.unwrap(), quirks_mode)
+ media_list.evaluate(&device, quirks_mode)
}
/// <https://html.spec.whatwg.org/multipage/#normalise-the-source-densities>
@@ -1039,9 +1045,12 @@ pub fn parse_a_sizes_attribute(value: DOMString) -> SourceSizeList {
Origin::Author,
&url,
Some(CssRuleType::Style),
+ // FIXME(emilio): why ::empty() instead of ::DEFAULT? Also, what do
+ // browsers do regarding quirks-mode in a media list?
ParsingMode::empty(),
QuirksMode::NoQuirks,
None,
+ None,
);
SourceSizeList::parse(&context, &mut parser)
}
@@ -1147,10 +1156,16 @@ impl HTMLImageElementMethods for HTMLImageElement {
// https://html.spec.whatwg.org/multipage/#dom-img-currentsrc
fn CurrentSrc(&self) -> DOMString {
- let ref url = self.current_request.borrow().source_url;
+ let ref url = self.current_request.borrow().parsed_url;
match *url {
- Some(ref url) => url.clone(),
- None => DOMString::from(""),
+ Some(ref url) => DOMString::from_string(url.clone().into_string()),
+ None => {
+ let ref unparsed_url = self.current_request.borrow().source_url;
+ match *unparsed_url {
+ Some(ref url) => url.clone(),
+ None => DOMString::from("")
+ }
+ },
}
}
diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs
index a86789dcd71..be7b2785ee9 100644
--- a/components/script/dom/htmllinkelement.rs
+++ b/components/script/dom/htmllinkelement.rs
@@ -287,6 +287,7 @@ impl HTMLLinkElement {
ParsingMode::DEFAULT,
document.quirks_mode(),
window.css_error_reporter(),
+ None,
);
let media = MediaList::parse(&context, &mut css_parser);
diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs
index 82da9ba6180..bcecab9088b 100644
--- a/components/script/dom/htmlstyleelement.rs
+++ b/components/script/dom/htmlstyleelement.rs
@@ -91,6 +91,7 @@ impl HTMLStyleElement {
ParsingMode::DEFAULT,
doc.quirks_mode(),
css_error_reporter,
+ None,
);
let shared_lock = node.owner_doc().style_shared_lock().clone();
let mut input = ParserInput::new(&mq_str);
diff --git a/components/script/dom/medialist.rs b/components/script/dom/medialist.rs
index d43f6d3a710..99800f1beb1 100644
--- a/components/script/dom/medialist.rs
+++ b/components/script/dom/medialist.rs
@@ -83,6 +83,7 @@ impl MediaListMethods for MediaList {
ParsingMode::DEFAULT,
quirks_mode,
window.css_error_reporter(),
+ None,
);
*media_queries = StyleMediaList::parse(&context, &mut parser);
}
@@ -123,6 +124,7 @@ impl MediaListMethods for MediaList {
ParsingMode::DEFAULT,
quirks_mode,
win.css_error_reporter(),
+ None,
);
let m = MediaQuery::parse(&context, &mut parser);
// Step 2
@@ -156,6 +158,7 @@ impl MediaListMethods for MediaList {
ParsingMode::DEFAULT,
quirks_mode,
win.css_error_reporter(),
+ None,
);
let m = MediaQuery::parse(&context, &mut parser);
// Step 2
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index 758c4284979..04a234a80d3 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -241,6 +241,7 @@ pub mod bluetoothuuid;
pub mod canvasgradient;
pub mod canvaspattern;
pub mod canvasrenderingcontext2d;
+pub mod channelmergernode;
pub mod characterdata;
pub mod client;
pub mod closeevent;
diff --git a/components/script/dom/offlineaudiocontext.rs b/components/script/dom/offlineaudiocontext.rs
index 4490d5df6f9..21376c11a4d 100644
--- a/components/script/dom/offlineaudiocontext.rs
+++ b/components/script/dom/offlineaudiocontext.rs
@@ -144,6 +144,10 @@ impl OfflineAudioContextMethods for OfflineAudioContext {
task!(resolve: move || {
let this = this.root();
let processed_audio = processed_audio.lock().unwrap();
+ let processed_audio: Vec<_> = processed_audio
+ .chunks(this.length as usize)
+ .map(|channel| channel.to_vec())
+ .collect();
let buffer = AudioBuffer::new(
&this.global().as_window(),
this.channel_count,
diff --git a/components/script/dom/oscillatornode.rs b/components/script/dom/oscillatornode.rs
index f44fa747f7d..662724c4438 100644
--- a/components/script/dom/oscillatornode.rs
+++ b/components/script/dom/oscillatornode.rs
@@ -35,7 +35,7 @@ impl OscillatorNode {
window: &Window,
context: &BaseAudioContext,
oscillator_options: &OscillatorOptions,
- ) -> OscillatorNode {
+ ) -> Fallible<OscillatorNode> {
let mut node_options = AudioNodeOptions::empty();
node_options.channelCount = Some(2);
node_options.channelCountMode = Some(ChannelCountMode::Max);
@@ -46,7 +46,7 @@ impl OscillatorNode {
&node_options,
0, /* inputs */
1, /* outputs */
- );
+ )?;
let node_id = source_node.node().node_id();
let frequency = AudioParam::new(
window,
@@ -69,12 +69,12 @@ impl OscillatorNode {
440. / 2.,
);
- OscillatorNode {
+ Ok(OscillatorNode {
source_node,
oscillator_type: oscillator_options.type_,
frequency: Dom::from_ref(&frequency),
detune: Dom::from_ref(&detune),
- }
+ })
}
#[allow(unrooted_must_root)]
@@ -82,9 +82,9 @@ impl OscillatorNode {
window: &Window,
context: &BaseAudioContext,
options: &OscillatorOptions,
- ) -> DomRoot<OscillatorNode> {
- let node = OscillatorNode::new_inherited(window, context, options);
- reflect_dom_object(Box::new(node), window, OscillatorNodeBinding::Wrap)
+ ) -> Fallible<DomRoot<OscillatorNode>> {
+ let node = OscillatorNode::new_inherited(window, context, options)?;
+ Ok(reflect_dom_object(Box::new(node), window, OscillatorNodeBinding::Wrap))
}
pub fn Constructor(
@@ -92,7 +92,7 @@ impl OscillatorNode {
context: &BaseAudioContext,
options: &OscillatorOptions,
) -> Fallible<DomRoot<OscillatorNode>> {
- Ok(OscillatorNode::new(window, context, options))
+ OscillatorNode::new(window, context, options)
}
}
diff --git a/components/script/dom/pannernode.rs b/components/script/dom/pannernode.rs
index 7f1909cdb50..a27388f2cab 100644
--- a/components/script/dom/pannernode.rs
+++ b/components/script/dom/pannernode.rs
@@ -54,16 +54,29 @@ impl PannerNode {
) -> Fallible<PannerNode> {
let count = options.parent.channelCount.unwrap_or(2);
let mode = options.parent.channelCountMode.unwrap_or(ChannelCountMode::Clamped_max);
+ let interpretation = options.parent.channelInterpretation.unwrap_or(ChannelInterpretation::Speakers);
if mode == ChannelCountMode::Max {
return Err(Error::NotSupported)
}
- if count > 2 {
+ if count > 2 || count == 0 {
return Err(Error::NotSupported)
}
+ if *options.maxDistance <= 0. {
+ return Err(Error::Range("maxDistance should be positive".into()))
+ }
+ if *options.refDistance < 0. {
+ return Err(Error::Range("refDistance should be non-negative".into()))
+ }
+ if *options.rolloffFactor < 0. {
+ return Err(Error::Range("rolloffFactor should be non-negative".into()))
+ }
+ if *options.coneOuterGain < 0. || *options.coneOuterGain > 1. {
+ return Err(Error::InvalidState)
+ }
let mut node_options = AudioNodeOptions::empty();
node_options.channelCount = Some(count);
node_options.channelCountMode = Some(mode);
- node_options.channelInterpretation = Some(ChannelInterpretation::Speakers);
+ node_options.channelInterpretation = Some(interpretation);
let options = options.into();
let node = AudioNode::new_inherited(
AudioNodeInit::PannerNode(options),
@@ -71,7 +84,7 @@ impl PannerNode {
&node_options,
1, // inputs
1, // outputs
- );
+ )?;
let id = node.node_id();
let position_x = AudioParam::new(
window,
@@ -230,10 +243,14 @@ impl PannerNodeMethods for PannerNode {
Finite::wrap(self.ref_distance.get())
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-refdistance
- fn SetRefDistance(&self, val: Finite<f64>) {
+ fn SetRefDistance(&self, val: Finite<f64>) -> Fallible<()> {
+ if *val < 0. {
+ return Err(Error::Range("value should be non-negative".into()))
+ }
self.ref_distance.set(*val);
let msg = PannerNodeMessage::SetRefDistance(self.ref_distance.get());
self.upcast::<AudioNode>().message(AudioNodeMessage::PannerNode(msg));
+ Ok(())
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-maxdistance
fn MaxDistance(&self) -> Finite<f64> {
@@ -241,8 +258,8 @@ impl PannerNodeMethods for PannerNode {
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-maxdistance
fn SetMaxDistance(&self, val: Finite<f64>) -> Fallible<()> {
- if *val < 0. {
- return Err(Error::NotSupported)
+ if *val <= 0. {
+ return Err(Error::Range("value should be positive".into()))
}
self.max_distance.set(*val);
let msg = PannerNodeMessage::SetMaxDistance(self.max_distance.get());
@@ -256,7 +273,7 @@ impl PannerNodeMethods for PannerNode {
// https://webaudio.github.io/web-audio-api/#dom-pannernode-rollofffactor
fn SetRolloffFactor(&self, val: Finite<f64>) -> Fallible<()> {
if *val < 0. {
- return Err(Error::Range("value should be positive".into()))
+ return Err(Error::Range("value should be non-negative".into()))
}
self.rolloff_factor.set(*val);
let msg = PannerNodeMessage::SetRolloff(self.rolloff_factor.get());
@@ -289,7 +306,7 @@ impl PannerNodeMethods for PannerNode {
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-coneoutergain
fn SetConeOuterGain(&self, val: Finite<f64>) -> Fallible<()> {
- if *val < 0. || *val > 360. {
+ if *val < 0. || *val > 1. {
return Err(Error::InvalidState)
}
self.cone_outer_gain.set(*val);
diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs
index 7e737b8d3d0..50080f9925b 100644
--- a/components/script/dom/serviceworkerglobalscope.rs
+++ b/components/script/dom/serviceworkerglobalscope.rs
@@ -5,17 +5,20 @@
use devtools;
use devtools_traits::DevtoolScriptControlMsg;
use dom::abstractworker::WorkerScriptMsg;
+use dom::abstractworkerglobalscope::{WorkerEventLoopMethods, run_worker_event_loop};
use dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding;
use dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding::ServiceWorkerGlobalScopeMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::reflector::DomObject;
use dom::bindings::root::{DomRoot, RootCollection, ThreadLocalStackRoots};
use dom::bindings::str::DOMString;
+use dom::dedicatedworkerglobalscope::AutoWorkerReset;
use dom::event::Event;
use dom::eventtarget::EventTarget;
use dom::extendableevent::ExtendableEvent;
use dom::extendablemessageevent::ExtendableMessageEvent;
use dom::globalscope::GlobalScope;
+use dom::worker::TrustedWorkerAddress;
use dom::workerglobalscope::WorkerGlobalScope;
use dom_struct::dom_struct;
use ipc_channel::ipc::{self, IpcSender, IpcReceiver};
@@ -29,17 +32,64 @@ use script_traits::{TimerEvent, WorkerGlobalScopeInit, ScopeThings, ServiceWorke
use servo_config::prefs::PREFS;
use servo_rand::random;
use servo_url::ServoUrl;
-use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel};
+use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread;
use std::time::Duration;
use style::thread_state::{self, ThreadState};
+use task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
+use task_source::TaskSourceName;
/// Messages used to control service worker event loop
pub enum ServiceWorkerScriptMsg {
/// Message common to all workers
CommonWorker(WorkerScriptMsg),
- // Message to request a custom response by the service worker
- Response(CustomResponseMediator)
+ /// Message to request a custom response by the service worker
+ Response(CustomResponseMediator),
+ /// Wake-up call from the task queue.
+ WakeUp,
+}
+
+impl QueuedTaskConversion for ServiceWorkerScriptMsg {
+ fn task_source_name(&self) -> Option<&TaskSourceName> {
+ let script_msg = match self {
+ ServiceWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(script_msg)) => script_msg,
+ _ => return None,
+ };
+ match script_msg {
+ CommonScriptMsg::Task(_category, _boxed, _pipeline_id, task_source) => Some(&task_source),
+ _ => return None,
+ }
+ }
+
+ fn into_queued_task(self) -> Option<QueuedTask> {
+ let script_msg = match self {
+ ServiceWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(script_msg)) => script_msg,
+ _ => return None,
+ };
+ let (category, boxed, pipeline_id, task_source) = match script_msg {
+ CommonScriptMsg::Task(category, boxed, pipeline_id, task_source) =>
+ (category, boxed, pipeline_id, task_source),
+ _ => return None,
+ };
+ Some((None, category, boxed, pipeline_id, task_source))
+ }
+
+ fn from_queued_task(queued_task: QueuedTask) -> Self {
+ let (_worker, category, boxed, pipeline_id, task_source) = queued_task;
+ let script_msg = CommonScriptMsg::Task(category, boxed, pipeline_id, task_source);
+ ServiceWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(script_msg))
+ }
+
+ fn wake_up_msg() -> Self {
+ ServiceWorkerScriptMsg::WakeUp
+ }
+
+ fn is_wake_up(&self) -> bool {
+ match self {
+ ServiceWorkerScriptMsg::WakeUp => true,
+ _ => false,
+ }
+ }
}
pub enum MixedMessage {
@@ -67,11 +117,13 @@ impl ScriptChan for ServiceWorkerChan {
}
}
+unsafe_no_jsmanaged_fields!(TaskQueue<ServiceWorkerScriptMsg>);
+
#[dom_struct]
pub struct ServiceWorkerGlobalScope {
workerglobalscope: WorkerGlobalScope,
#[ignore_malloc_size_of = "Defined in std"]
- receiver: Receiver<ServiceWorkerScriptMsg>,
+ task_queue: TaskQueue<ServiceWorkerScriptMsg>,
#[ignore_malloc_size_of = "Defined in std"]
own_sender: Sender<ServiceWorkerScriptMsg>,
#[ignore_malloc_size_of = "Defined in std"]
@@ -81,6 +133,40 @@ pub struct ServiceWorkerGlobalScope {
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
+ }
+
+ fn handle_event(&self, event: MixedMessage) {
+ self.handle_mixed_message(event);
+ }
+
+ fn handle_worker_post_event(&self, _worker: &TrustedWorkerAddress) -> Option<AutoWorkerReset> {
+ None
+ }
+
+ fn from_worker_msg(&self, msg: ServiceWorkerScriptMsg) -> MixedMessage {
+ MixedMessage::FromServiceWorker(msg)
+ }
+
+ fn from_timer_msg(&self, msg: ()) -> MixedMessage {
+ MixedMessage::FromTimeoutThread(msg)
+ }
+
+ fn from_devtools_msg(&self, msg: DevtoolScriptControlMsg) -> MixedMessage {
+ MixedMessage::FromDevtools(msg)
+ }
+}
+
impl ServiceWorkerGlobalScope {
fn new_inherited(init: WorkerGlobalScopeInit,
worker_url: ServoUrl,
@@ -100,7 +186,7 @@ impl ServiceWorkerGlobalScope {
from_devtools_receiver,
timer_event_chan,
None),
- receiver: receiver,
+ task_queue: TaskQueue::new(receiver, own_sender.clone()),
timer_event_port: timer_event_port,
own_sender: own_sender,
swmanager_sender: swmanager_sender,
@@ -139,6 +225,7 @@ impl ServiceWorkerGlobalScope {
}
#[allow(unsafe_code)]
+ // https://html.spec.whatwg.org/multipage/#run-a-worker
pub fn run_serviceworker_scope(scope_things: ScopeThings,
own_sender: Sender<ServiceWorkerScriptMsg>,
receiver: Receiver<ServiceWorkerScriptMsg>,
@@ -211,22 +298,18 @@ impl ServiceWorkerGlobalScope {
global.dispatch_activate();
let reporter_name = format!("service-worker-reporter-{}", random::<u64>());
scope.upcast::<GlobalScope>().mem_profiler_chan().run_with_memory_reporting(|| {
- // https://html.spec.whatwg.org/multipage/#event-loop-processing-model
- // Step 1
- while let Ok(event) = global.receive_event() {
- // Step 3
- if !global.handle_event(event) {
- break;
- }
- // Step 6
- global.upcast::<GlobalScope>().perform_a_microtask_checkpoint();
+ // Step 29, Run the responsible event loop specified 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() {
+ run_worker_event_loop(&*global, None);
}
}, reporter_name, scope.script_chan(), CommonScriptMsg::CollectReports);
}).expect("Thread spawning failed");
}
- fn handle_event(&self, event: MixedMessage) -> bool {
- match event {
+ fn handle_mixed_message(&self, msg: MixedMessage) -> bool {
+ match msg {
MixedMessage::FromDevtools(msg) => {
match msg {
DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) =>
@@ -271,38 +354,8 @@ impl ServiceWorkerGlobalScope {
// https://slightlyoff.github.io/ServiceWorker/spec/service_worker_1/index.html#fetch-event-section
self.upcast::<EventTarget>().fire_event(atom!("fetch"));
let _ = mediator.response_chan.send(None);
- }
- }
- }
-
- #[allow(unsafe_code)]
- fn receive_event(&self) -> Result<MixedMessage, RecvError> {
- let scope = self.upcast::<WorkerGlobalScope>();
- let worker_port = &self.receiver;
- let devtools_port = scope.from_devtools_receiver();
- let timer_event_port = &self.timer_event_port;
-
- let sel = Select::new();
- let mut worker_handle = sel.handle(worker_port);
- let mut devtools_handle = sel.handle(devtools_port);
- let mut timer_port_handle = sel.handle(timer_event_port);
- unsafe {
- worker_handle.add();
- if scope.from_devtools_sender().is_some() {
- devtools_handle.add();
- }
- timer_port_handle.add();
- }
-
- let ret = sel.wait();
- if ret == worker_handle.id() {
- Ok(MixedMessage::FromServiceWorker(worker_port.recv()?))
- }else if ret == devtools_handle.id() {
- Ok(MixedMessage::FromDevtools(devtools_port.recv()?))
- } else if ret == timer_port_handle.id() {
- Ok(MixedMessage::FromTimeoutThread(timer_event_port.recv()?))
- } else {
- panic!("unexpected select result!")
+ },
+ WakeUp => {},
}
}
diff --git a/components/script/dom/vrdisplay.rs b/components/script/dom/vrdisplay.rs
index c9f24d04ffa..397ec725a4d 100644
--- a/components/script/dom/vrdisplay.rs
+++ b/components/script/dom/vrdisplay.rs
@@ -42,6 +42,7 @@ use std::ops::Deref;
use std::rc::Rc;
use std::sync::mpsc;
use std::thread;
+use task_source::TaskSourceName;
use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVRFrameData, WebVRLayer, WebVRMsg};
#[dom_struct]
@@ -517,7 +518,14 @@ impl VRDisplay {
let task = Box::new(task!(handle_vrdisplay_raf: move || {
this.root().handle_raf(&sender);
}));
- js_sender.send(CommonScriptMsg::Task(WebVREvent, task, Some(pipeline_id))).unwrap();
+ // NOTE: WebVR spec doesn't specify what task source we should use. Is
+ // dom-manipulation a good choice long term?
+ js_sender.send(CommonScriptMsg::Task(
+ WebVREvent,
+ task,
+ Some(pipeline_id),
+ TaskSourceName::DOMManipulation,
+ )).unwrap();
// Run Sync Poses in parallell on Render thread
let msg = WebVRCommand::SyncPoses(display_id, near, far, sync_sender.clone());
diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs
index 811fc100e6b..da50ed556df 100644
--- a/components/script/dom/webgl2renderingcontext.rs
+++ b/components/script/dom/webgl2renderingcontext.rs
@@ -240,14 +240,18 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
self.base.GenerateMipmap(target)
}
- #[allow(unsafe_code)]
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
- unsafe fn BufferData(&self, cx: *mut JSContext, target: u32, data: *mut JSObject, usage: u32) -> Fallible<()> {
- self.base.BufferData(cx, target, data, usage)
+ fn BufferData(
+ &self,
+ target: u32,
+ data: Option<ArrayBufferViewOrArrayBuffer>,
+ usage: u32,
+ ) {
+ self.base.BufferData(target, data, usage)
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
- fn BufferData_(&self, target: u32, size: i64, usage: u32) -> Fallible<()> {
+ fn BufferData_(&self, target: u32, size: i64, usage: u32) {
self.base.BufferData_(target, size, usage)
}
@@ -957,7 +961,10 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
count: i32,
primcount: i32,
) {
- self.base.draw_arrays_instanced(mode, first, count, primcount);
+ handle_potential_webgl_error!(
+ self.base,
+ self.base.draw_arrays_instanced(mode, first, count, primcount)
+ )
}
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.9
@@ -969,7 +976,10 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
offset: i64,
primcount: i32,
) {
- self.base.draw_elements_instanced(mode, count, type_, offset, primcount);
+ handle_potential_webgl_error!(
+ self.base,
+ self.base.draw_elements_instanced(mode, count, type_, offset, primcount)
+ )
}
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.9
diff --git a/components/script/dom/webgl_extensions/ext/angleinstancedarrays.rs b/components/script/dom/webgl_extensions/ext/angleinstancedarrays.rs
index f35abaf15af..7c93c8c6567 100644
--- a/components/script/dom/webgl_extensions/ext/angleinstancedarrays.rs
+++ b/components/script/dom/webgl_extensions/ext/angleinstancedarrays.rs
@@ -71,7 +71,10 @@ impl ANGLEInstancedArraysMethods for ANGLEInstancedArrays {
count: i32,
primcount: i32,
) {
- self.ctx.draw_arrays_instanced(mode, first, count, primcount);
+ handle_potential_webgl_error!(
+ self.ctx,
+ self.ctx.draw_arrays_instanced(mode, first, count, primcount)
+ )
}
// https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
@@ -83,7 +86,10 @@ impl ANGLEInstancedArraysMethods for ANGLEInstancedArrays {
offset: i64,
primcount: i32,
) {
- self.ctx.draw_elements_instanced(mode, count, type_, offset, primcount);
+ handle_potential_webgl_error!(
+ self.ctx,
+ self.ctx.draw_elements_instanced(mode, count, type_, offset, primcount)
+ )
}
fn VertexAttribDivisorANGLE(&self, index: u32, divisor: u32) {
diff --git a/components/script/dom/webglbuffer.rs b/components/script/dom/webglbuffer.rs
index 66a3ce0af40..c49a3852709 100644
--- a/components/script/dom/webglbuffer.rs
+++ b/components/script/dom/webglbuffer.rs
@@ -13,6 +13,7 @@ use dom::bindings::root::DomRoot;
use dom::webglobject::WebGLObject;
use dom::webglrenderingcontext::WebGLRenderingContext;
use dom_struct::dom_struct;
+use ipc_channel::ipc;
use std::cell::Cell;
#[dom_struct]
@@ -62,10 +63,7 @@ impl WebGLBuffer {
self.id
}
- pub fn buffer_data<T>(&self, target: u32, data: T, usage: u32) -> WebGLResult<()>
- where
- T: Into<Vec<u8>>,
- {
+ pub fn buffer_data(&self, data: &[u8], usage: u32) -> WebGLResult<()> {
match usage {
WebGLRenderingContextConstants::STREAM_DRAW |
WebGLRenderingContextConstants::STATIC_DRAW |
@@ -73,17 +71,13 @@ impl WebGLBuffer {
_ => return Err(WebGLError::InvalidEnum),
}
- if let Some(previous_target) = self.target.get() {
- if target != previous_target {
- return Err(WebGLError::InvalidOperation);
- }
- }
- let data = data.into();
self.capacity.set(data.len());
self.usage.set(usage);
+ let (sender, receiver) = ipc::bytes_channel().unwrap();
self.upcast::<WebGLObject>()
.context()
- .send_command(WebGLCommand::BufferData(target, data.into(), usage));
+ .send_command(WebGLCommand::BufferData(self.target.get().unwrap(), receiver, usage));
+ sender.send(data).unwrap();
Ok(())
}
@@ -154,6 +148,7 @@ impl WebGLBuffer {
impl Drop for WebGLBuffer {
fn drop(&mut self) {
- self.delete();
+ self.mark_for_deletion();
+ assert!(self.is_deleted());
}
}
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 4aa6c047a1b..ab7178ffa16 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -2,7 +2,7 @@
* 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 byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
+use byteorder::{ByteOrder, NativeEndian, WriteBytesExt};
use canvas_traits::canvas::{byte_swap, multiply_u8_pixel};
use canvas_traits::webgl::{DOMToTextureCommand, Parameter};
use canvas_traits::webgl::{TexParameter, WebGLCommand, WebGLContextShareMode, WebGLError};
@@ -52,6 +52,7 @@ use dom::window::Window;
use dom_struct::dom_struct;
use euclid::Size2D;
use half::f16;
+use ipc_channel::ipc;
use js::jsapi::{JSContext, JSObject, Type};
use js::jsval::{BooleanValue, DoubleValue, Int32Value, UInt32Value, JSVal};
use js::jsval::{ObjectValue, NullValue, UndefinedValue};
@@ -336,17 +337,12 @@ impl WebGLRenderingContext {
//
// The WebGL spec mentions a couple more operations that trigger
// this: clear() and getParameter(IMPLEMENTATION_COLOR_READ_*).
- fn validate_framebuffer_complete(&self) -> bool {
+ fn validate_framebuffer(&self) -> WebGLResult<()> {
match self.bound_framebuffer.get() {
- Some(fb) => match fb.check_status() {
- constants::FRAMEBUFFER_COMPLETE => return true,
- _ => {
- self.webgl_error(InvalidFramebufferOperation);
- return false;
- }
+ Some(ref fb) if fb.check_status() != constants::FRAMEBUFFER_COMPLETE => {
+ Err(InvalidFramebufferOperation)
},
- // The default framebuffer is always complete.
- None => return true,
+ _ => Ok(()),
}
}
@@ -485,206 +481,6 @@ impl WebGLRenderingContext {
}
}
- // https://en.wikipedia.org/wiki/Relative_luminance
- #[inline]
- fn luminance(r: u8, g: u8, b: u8) -> u8 {
- (0.2126 * (r as f32) +
- 0.7152 * (g as f32) +
- 0.0722 * (b as f32)) as u8
- }
-
- /// Translates an image in rgba8 (red in the first byte) format to
- /// the format that was requested of TexImage.
- ///
- /// From the WebGL 1.0 spec, 5.14.8:
- ///
- /// "The source image data is conceptually first converted to
- /// the data type and format specified by the format and type
- /// arguments, and then transferred to the WebGL
- /// implementation. If a packed pixel format is specified
- /// which would imply loss of bits of precision from the image
- /// data, this loss of precision must occur."
- fn rgba8_image_to_tex_image_data(&self,
- format: TexFormat,
- data_type: TexDataType,
- pixels: Vec<u8>) -> Vec<u8> {
- // hint for vector allocation sizing.
- let pixel_count = pixels.len() / 4;
-
- match (format, data_type) {
- (TexFormat::RGBA, TexDataType::UnsignedByte) => pixels,
- (TexFormat::RGB, TexDataType::UnsignedByte) => {
- // Remove alpha channel
- let mut rgb8 = Vec::<u8>::with_capacity(pixel_count * 3);
- for rgba8 in pixels.chunks(4) {
- rgb8.push(rgba8[0]);
- rgb8.push(rgba8[1]);
- rgb8.push(rgba8[2]);
- }
- rgb8
- },
-
- (TexFormat::Alpha, TexDataType::UnsignedByte) => {
- let mut alpha = Vec::<u8>::with_capacity(pixel_count);
- for rgba8 in pixels.chunks(4) {
- alpha.push(rgba8[3]);
- }
- alpha
- },
-
- (TexFormat::Luminance, TexDataType::UnsignedByte) => {
- let mut luminance = Vec::<u8>::with_capacity(pixel_count);
- for rgba8 in pixels.chunks(4) {
- luminance.push(Self::luminance(rgba8[0], rgba8[1], rgba8[2]));
- }
- luminance
- },
-
- (TexFormat::LuminanceAlpha, TexDataType::UnsignedByte) => {
- let mut data = Vec::<u8>::with_capacity(pixel_count * 2);
- for rgba8 in pixels.chunks(4) {
- data.push(Self::luminance(rgba8[0], rgba8[1], rgba8[2]));
- data.push(rgba8[3]);
- }
- data
- },
-
- (TexFormat::RGBA, TexDataType::UnsignedShort4444) => {
- let mut rgba4 = Vec::<u8>::with_capacity(pixel_count * 2);
- for rgba8 in pixels.chunks(4) {
- rgba4.write_u16::<NativeEndian>((rgba8[0] as u16 & 0xf0) << 8 |
- (rgba8[1] as u16 & 0xf0) << 4 |
- (rgba8[2] as u16 & 0xf0) |
- (rgba8[3] as u16 & 0xf0) >> 4).unwrap();
- }
- rgba4
- }
-
- (TexFormat::RGBA, TexDataType::UnsignedShort5551) => {
- let mut rgba5551 = Vec::<u8>::with_capacity(pixel_count * 2);
- for rgba8 in pixels.chunks(4) {
- rgba5551.write_u16::<NativeEndian>((rgba8[0] as u16 & 0xf8) << 8 |
- (rgba8[1] as u16 & 0xf8) << 3 |
- (rgba8[2] as u16 & 0xf8) >> 2 |
- (rgba8[3] as u16) >> 7).unwrap();
- }
- rgba5551
- }
-
- (TexFormat::RGB, TexDataType::UnsignedShort565) => {
- let mut rgb565 = Vec::<u8>::with_capacity(pixel_count * 2);
- for rgba8 in pixels.chunks(4) {
- rgb565.write_u16::<NativeEndian>((rgba8[0] as u16 & 0xf8) << 8 |
- (rgba8[1] as u16 & 0xfc) << 3 |
- (rgba8[2] as u16 & 0xf8) >> 3).unwrap();
- }
- rgb565
- }
-
-
- (TexFormat::RGBA, TexDataType::Float) => {
- let mut rgbaf32 = Vec::<u8>::with_capacity(pixel_count * 16);
- for rgba8 in pixels.chunks(4) {
- rgbaf32.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap();
- rgbaf32.write_f32::<NativeEndian>(rgba8[1] as f32).unwrap();
- rgbaf32.write_f32::<NativeEndian>(rgba8[2] as f32).unwrap();
- rgbaf32.write_f32::<NativeEndian>(rgba8[3] as f32).unwrap();
- }
- rgbaf32
- }
-
- (TexFormat::RGB, TexDataType::Float) => {
- let mut rgbf32 = Vec::<u8>::with_capacity(pixel_count * 12);
- for rgba8 in pixels.chunks(4) {
- rgbf32.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap();
- rgbf32.write_f32::<NativeEndian>(rgba8[1] as f32).unwrap();
- rgbf32.write_f32::<NativeEndian>(rgba8[2] as f32).unwrap();
- }
- rgbf32
- }
-
- (TexFormat::Alpha, TexDataType::Float) => {
- let mut alpha = Vec::<u8>::with_capacity(pixel_count * 4);
- for rgba8 in pixels.chunks(4) {
- alpha.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap();
- }
- alpha
- },
-
- (TexFormat::Luminance, TexDataType::Float) => {
- let mut luminance = Vec::<u8>::with_capacity(pixel_count * 4);
- for rgba8 in pixels.chunks(4) {
- let p = Self::luminance(rgba8[0], rgba8[1], rgba8[2]);
- luminance.write_f32::<NativeEndian>(p as f32).unwrap();
- }
- luminance
- },
-
- (TexFormat::LuminanceAlpha, TexDataType::Float) => {
- let mut data = Vec::<u8>::with_capacity(pixel_count * 8);
- for rgba8 in pixels.chunks(4) {
- let p = Self::luminance(rgba8[0], rgba8[1], rgba8[2]);
- data.write_f32::<NativeEndian>(p as f32).unwrap();
- data.write_f32::<NativeEndian>(rgba8[3] as f32).unwrap();
- }
- data
- },
-
- (TexFormat::RGBA, TexDataType::HalfFloat) => {
- let mut rgbaf16 = Vec::<u8>::with_capacity(pixel_count * 8);
- for rgba8 in pixels.chunks(4) {
- rgbaf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[0] as f32).as_bits()).unwrap();
- rgbaf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[1] as f32).as_bits()).unwrap();
- rgbaf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[2] as f32).as_bits()).unwrap();
- rgbaf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[3] as f32).as_bits()).unwrap();
- }
- rgbaf16
- },
-
- (TexFormat::RGB, TexDataType::HalfFloat) => {
- let mut rgbf16 = Vec::<u8>::with_capacity(pixel_count * 6);
- for rgba8 in pixels.chunks(4) {
- rgbf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[0] as f32).as_bits()).unwrap();
- rgbf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[1] as f32).as_bits()).unwrap();
- rgbf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[2] as f32).as_bits()).unwrap();
- }
- rgbf16
- },
-
- (TexFormat::Alpha, TexDataType::HalfFloat) => {
- let mut alpha = Vec::<u8>::with_capacity(pixel_count * 2);
- for rgba8 in pixels.chunks(4) {
- alpha.write_u16::<NativeEndian>(f16::from_f32(rgba8[3] as f32).as_bits()).unwrap();
- }
- alpha
- },
-
- (TexFormat::Luminance, TexDataType::HalfFloat) => {
- let mut luminance = Vec::<u8>::with_capacity(pixel_count * 4);
- for rgba8 in pixels.chunks(4) {
- let p = Self::luminance(rgba8[0], rgba8[1], rgba8[2]);
- luminance.write_u16::<NativeEndian>(f16::from_f32(p as f32).as_bits()).unwrap();
- }
- luminance
- },
-
- (TexFormat::LuminanceAlpha, TexDataType::HalfFloat) => {
- let mut data = Vec::<u8>::with_capacity(pixel_count * 8);
- for rgba8 in pixels.chunks(4) {
- let p = Self::luminance(rgba8[0], rgba8[1], rgba8[2]);
- data.write_u16::<NativeEndian>(f16::from_f32(p as f32).as_bits()).unwrap();
- data.write_u16::<NativeEndian>(f16::from_f32(rgba8[3] as f32).as_bits()).unwrap();
- }
- data
- },
-
- // Validation should have ensured that we only hit the
- // above cases, but we haven't turned the (format, type)
- // into an enum yet so there's a default case here.
- _ => unreachable!("Unsupported formats {:?} {:?}", format, data_type)
- }
- }
-
fn get_image_pixels(
&self,
source: ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement,
@@ -829,83 +625,51 @@ impl WebGLRenderingContext {
/// Performs premultiplication of the pixels if
/// UNPACK_PREMULTIPLY_ALPHA_WEBGL is currently enabled.
- fn premultiply_pixels(&self,
- format: TexFormat,
- data_type: TexDataType,
- pixels: Vec<u8>) -> Vec<u8> {
+ fn premultiply_pixels(&self, format: TexFormat, data_type: TexDataType, pixels: &mut [u8]) {
if !self.texture_unpacking_settings.get().contains(TextureUnpacking::PREMULTIPLY_ALPHA) {
- return pixels;
+ return;
}
match (format, data_type) {
(TexFormat::RGBA, TexDataType::UnsignedByte) => {
- let mut premul = Vec::<u8>::with_capacity(pixels.len());
- for rgba in pixels.chunks(4) {
- premul.push(multiply_u8_pixel(rgba[0], rgba[3]));
- premul.push(multiply_u8_pixel(rgba[1], rgba[3]));
- premul.push(multiply_u8_pixel(rgba[2], rgba[3]));
- premul.push(rgba[3]);
+ for rgba in pixels.chunks_mut(4) {
+ rgba[0] = multiply_u8_pixel(rgba[0], rgba[3]);
+ rgba[1] = multiply_u8_pixel(rgba[1], rgba[3]);
+ rgba[2] = multiply_u8_pixel(rgba[2], rgba[3]);
}
- premul
- }
+ },
(TexFormat::LuminanceAlpha, TexDataType::UnsignedByte) => {
- let mut premul = Vec::<u8>::with_capacity(pixels.len());
- for la in pixels.chunks(2) {
- premul.push(multiply_u8_pixel(la[0], la[1]));
- premul.push(la[1]);
+ for la in pixels.chunks_mut(2) {
+ la[0] = multiply_u8_pixel(la[0], la[1]);
}
- premul
- }
-
+ },
(TexFormat::RGBA, TexDataType::UnsignedShort5551) => {
- let mut premul = Vec::<u8>::with_capacity(pixels.len());
- for mut rgba in pixels.chunks(2) {
- let pix = rgba.read_u16::<NativeEndian>().unwrap();
- if pix & (1 << 15) != 0 {
- premul.write_u16::<NativeEndian>(pix).unwrap();
- } else {
- premul.write_u16::<NativeEndian>(0).unwrap();
+ for rgba in pixels.chunks_mut(2) {
+ if NativeEndian::read_u16(rgba) & 1 == 0 {
+ NativeEndian::write_u16(rgba, 0);
}
}
- premul
- }
-
+ },
(TexFormat::RGBA, TexDataType::UnsignedShort4444) => {
- let mut premul = Vec::<u8>::with_capacity(pixels.len());
- for mut rgba in pixels.chunks(2) {
- let pix = rgba.read_u16::<NativeEndian>().unwrap();
- let extend_to_8_bits = |val| { (val | val << 4) as u8 };
- let r = extend_to_8_bits(pix & 0x000f);
- let g = extend_to_8_bits((pix & 0x00f0) >> 4);
- let b = extend_to_8_bits((pix & 0x0f00) >> 8);
- let a = extend_to_8_bits((pix & 0xf000) >> 12);
-
- premul.write_u16::<NativeEndian>((multiply_u8_pixel(r, a) & 0xf0) as u16 >> 4 |
- (multiply_u8_pixel(g, a) & 0xf0) as u16 |
- ((multiply_u8_pixel(b, a) & 0xf0) as u16) << 4 |
- pix & 0xf000).unwrap();
+ for rgba in pixels.chunks_mut(2) {
+ let pix = NativeEndian::read_u16(rgba);
+ let extend_to_8_bits = |val| (val | val << 4) as u8;
+ let r = extend_to_8_bits(pix >> 12 & 0x0f);
+ let g = extend_to_8_bits(pix >> 8 & 0x0f);
+ let b = extend_to_8_bits(pix >> 4 & 0x0f);
+ let a = extend_to_8_bits(pix & 0x0f);
+ NativeEndian::write_u16(
+ rgba,
+ ((multiply_u8_pixel(r, a) & 0xf0) as u16) << 8 |
+ ((multiply_u8_pixel(g, a) & 0xf0) as u16) << 4 |
+ ((multiply_u8_pixel(b, a) & 0xf0) as u16) |
+ ((a & 0x0f) as u16),
+ );
}
- premul
- }
-
+ },
// Other formats don't have alpha, so return their data untouched.
- _ => pixels
- }
- }
-
- // Remove premultiplied alpha.
- // This is only called when texImage2D is called using a canvas2d source and
- // UNPACK_PREMULTIPLY_ALPHA_WEBGL is disabled. Pixels got from a canvas2D source
- // are always RGBA8 with premultiplied alpha, so we don't have to worry about
- // additional formats as happens in the premultiply_pixels method.
- fn remove_premultiplied_alpha(&self, mut pixels: Vec<u8>) -> Vec<u8> {
- for rgba in pixels.chunks_mut(4) {
- let a = (rgba[3] as f32) / 255.0;
- rgba[0] = (rgba[0] as f32 / a) as u8;
- rgba[1] = (rgba[1] as f32 / a) as u8;
- rgba[2] = (rgba[2] as f32 / a) as u8;
+ _ => {},
}
- pixels
}
fn prepare_pixels(&self,
@@ -921,16 +685,16 @@ impl WebGLRenderingContext {
if !source_premultiplied && dest_premultiply {
if source_from_image_or_canvas {
// When the pixels come from image or canvas or imagedata, use RGBA8 format
- pixels = self.premultiply_pixels(TexFormat::RGBA, TexDataType::UnsignedByte, pixels);
+ self.premultiply_pixels(TexFormat::RGBA, TexDataType::UnsignedByte, &mut pixels);
} else {
- pixels = self.premultiply_pixels(internal_format, data_type, pixels);
+ self.premultiply_pixels(internal_format, data_type, &mut pixels);
}
} else if source_premultiplied && !dest_premultiply {
- pixels = self.remove_premultiplied_alpha(pixels);
+ remove_premultiplied_alpha(&mut pixels);
}
if source_from_image_or_canvas {
- pixels = self.rgba8_image_to_tex_image_data(internal_format, data_type, pixels);
+ pixels = rgba8_image_to_tex_image_data(internal_format, data_type, pixels);
}
// FINISHME: Consider doing premultiply and flip in a single mutable Vec.
@@ -970,17 +734,17 @@ impl WebGLRenderingContext {
let internal_format = self.extension_manager.get_effective_tex_internal_format(format, data_type);
// TODO(emilio): convert colorspace if requested
- let msg = WebGLCommand::TexImage2D(
+ let (sender, receiver) = ipc::bytes_channel().unwrap();
+ self.send_command(WebGLCommand::TexImage2D(
target.as_gl_constant(),
level as i32,
internal_format as i32,
width as i32, height as i32,
format,
data_type,
- pixels.into(),
- );
-
- self.send_command(msg);
+ receiver,
+ ));
+ sender.send(&pixels).unwrap();
if let Some(fb) = self.bound_framebuffer.get() {
fb.invalidate_texture(&*texture);
@@ -1025,7 +789,8 @@ impl WebGLRenderingContext {
self.send_command(WebGLCommand::PixelStorei(constants::UNPACK_ALIGNMENT, unpacking_alignment as i32));
// TODO(emilio): convert colorspace if requested
- let msg = WebGLCommand::TexSubImage2D(
+ let (sender, receiver) = ipc::bytes_channel().unwrap();
+ self.send_command(WebGLCommand::TexSubImage2D(
target.as_gl_constant(),
level as i32,
xoffset,
@@ -1034,10 +799,9 @@ impl WebGLRenderingContext {
height as i32,
format.as_gl_constant(),
data_type.as_gl_constant(),
- pixels.into(),
- );
-
- self.send_command(msg);
+ receiver,
+ ));
+ sender.send(&pixels).unwrap();
}
fn get_gl_extensions(&self) -> String {
@@ -1076,48 +840,38 @@ impl WebGLRenderingContext {
first: i32,
count: i32,
primcount: i32,
- ) {
+ ) -> WebGLResult<()> {
match mode {
constants::POINTS | constants::LINE_STRIP |
constants::LINE_LOOP | constants::LINES |
constants::TRIANGLE_STRIP | constants::TRIANGLE_FAN |
constants::TRIANGLES => {},
_ => {
- return self.webgl_error(InvalidEnum);
+ return Err(InvalidEnum);
}
}
if first < 0 || count < 0 || primcount < 0 {
- return self.webgl_error(InvalidValue);
+ return Err(InvalidValue);
}
- let current_program = handle_potential_webgl_error!(
- self,
- self.current_program.get().ok_or(InvalidOperation),
- return
- );
+ let current_program = self.current_program.get().ok_or(InvalidOperation)?;
let required_len = if count > 0 {
- handle_potential_webgl_error!(
- self,
- first.checked_add(count).map(|len| len as u32).ok_or(InvalidOperation),
- return
- )
+ first.checked_add(count).map(|len| len as u32).ok_or(InvalidOperation)?
} else {
0
};
- handle_potential_webgl_error!(
- self,
- self.current_vao().validate_for_draw(required_len, primcount as u32, &current_program.active_attribs()),
- return
- );
+ self.current_vao().validate_for_draw(
+ required_len,
+ primcount as u32,
+ &current_program.active_attribs(),
+ )?;
- if !self.validate_framebuffer_complete() {
- return;
- }
+ self.validate_framebuffer()?;
if count == 0 || primcount == 0 {
- return;
+ return Ok(());
}
self.send_command(if primcount == 1 {
@@ -1126,6 +880,7 @@ impl WebGLRenderingContext {
WebGLCommand::DrawArraysInstanced { mode, first, count, primcount }
});
self.mark_as_dirty();
+ Ok(())
}
// https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
@@ -1136,60 +891,47 @@ impl WebGLRenderingContext {
type_: u32,
offset: i64,
primcount: i32,
- ) {
+ ) -> WebGLResult<()> {
match mode {
constants::POINTS | constants::LINE_STRIP |
constants::LINE_LOOP | constants::LINES |
constants::TRIANGLE_STRIP | constants::TRIANGLE_FAN |
constants::TRIANGLES => {},
_ => {
- return self.webgl_error(InvalidEnum);
+ return Err(InvalidEnum);
}
}
if count < 0 || offset < 0 || primcount < 0 {
- return self.webgl_error(InvalidValue);
+ return Err(InvalidValue);
}
let type_size = match type_ {
constants::UNSIGNED_BYTE => 1,
constants::UNSIGNED_SHORT => 2,
constants::UNSIGNED_INT if self.extension_manager.is_element_index_uint_enabled() => 4,
- _ => return self.webgl_error(InvalidEnum),
+ _ => return Err(InvalidEnum),
};
if offset % type_size != 0 {
- return self.webgl_error(InvalidOperation);
+ return Err(InvalidOperation);
}
- let current_program = handle_potential_webgl_error!(
- self,
- self.current_program.get().ok_or(InvalidOperation),
- return
- );
+ let current_program = self.current_program.get().ok_or(InvalidOperation)?;
+ let array_buffer = self.current_vao().element_array_buffer().get().ok_or(InvalidOperation)?;
if count > 0 && primcount > 0 {
- if let Some(array_buffer) = self.current_vao().element_array_buffer().get() {
- // This operation cannot overflow in u64 and we know all those values are nonnegative.
- let val = offset as u64 + (count as u64 * type_size as u64);
- if val > array_buffer.capacity() as u64 {
- return self.webgl_error(InvalidOperation);
- }
- } else {
- return self.webgl_error(InvalidOperation);
+ // This operation cannot overflow in u64 and we know all those values are nonnegative.
+ let val = offset as u64 + (count as u64 * type_size as u64);
+ if val > array_buffer.capacity() as u64 {
+ return Err(InvalidOperation);
}
}
// TODO(nox): Pass the correct number of vertices required.
- handle_potential_webgl_error!(
- self,
- self.current_vao().validate_for_draw(0, primcount as u32, &current_program.active_attribs()),
- return
- );
+ self.current_vao().validate_for_draw(0, primcount as u32, &current_program.active_attribs())?;
- if !self.validate_framebuffer_complete() {
- return;
- }
+ self.validate_framebuffer()?;
if count == 0 || primcount == 0 {
- return;
+ return Ok(());
}
let offset = offset as u32;
@@ -1199,6 +941,7 @@ impl WebGLRenderingContext {
WebGLCommand::DrawElementsInstanced { mode, count, type_, offset, primcount }
});
self.mark_as_dirty();
+ Ok(())
}
pub fn vertex_attrib_divisor(&self, index: u32, divisor: u32) {
@@ -1216,20 +959,18 @@ impl WebGLRenderingContext {
// can fail and that it is UB what happens in that case.
//
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#2.2
- pub fn get_image_data(&self, mut width: u32, mut height: u32) -> Option<Vec<u8>> {
- if !self.validate_framebuffer_complete() {
- return None;
- }
+ pub fn get_image_data(&self, width: u32, height: u32) -> Option<Vec<u8>> {
+ handle_potential_webgl_error!(self, self.validate_framebuffer(), return None);
- if let Some((fb_width, fb_height)) = self.get_current_framebuffer_size() {
- width = cmp::min(width, fb_width as u32);
- height = cmp::min(height, fb_height as u32);
- } else {
- self.webgl_error(InvalidOperation);
- return None;
- }
+ let (fb_width, fb_height) = handle_potential_webgl_error!(
+ self,
+ self.get_current_framebuffer_size().ok_or(InvalidOperation),
+ return None
+ );
+ let width = cmp::min(width, fb_width as u32);
+ let height = cmp::min(height, fb_height as u32);
- let (sender, receiver) = webgl_channel().unwrap();
+ let (sender, receiver) = ipc::bytes_channel().unwrap();
self.send_command(WebGLCommand::ReadPixels(
0,
0,
@@ -1239,7 +980,7 @@ impl WebGLRenderingContext {
constants::UNSIGNED_BYTE,
sender,
));
- Some(receiver.recv().unwrap().into())
+ Some(receiver.recv().unwrap())
}
pub fn array_buffer(&self) -> Option<DomRoot<WebGLBuffer>> {
@@ -1324,19 +1065,6 @@ impl Drop for WebGLRenderingContext {
}
}
-#[allow(unsafe_code)]
-unsafe fn fallible_array_buffer_view_to_vec(
- cx: *mut JSContext,
- abv: *mut JSObject,
-) -> Result<Vec<u8>, Error> {
- assert!(!abv.is_null());
- typedarray!(in(cx) let array_buffer_view: ArrayBufferView = abv);
- match array_buffer_view {
- Ok(v) => Ok(v.to_vec()),
- Err(_) => Err(Error::Type("Not an ArrayBufferView".to_owned())),
- }
-}
-
impl WebGLRenderingContextMethods for WebGLRenderingContext {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.1
fn Canvas(&self) -> DomRoot<HTMLCanvasElement> {
@@ -1436,18 +1164,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// GL_OES_read_format support (assuming an underlying GLES
// driver. Desktop is happy to format convert for us).
constants::IMPLEMENTATION_COLOR_READ_FORMAT => {
- if !self.validate_framebuffer_complete() {
- return NullValue();
- } else {
- return Int32Value(constants::RGBA as i32);
- }
+ handle_potential_webgl_error!(self, self.validate_framebuffer(), return NullValue());
+ return Int32Value(constants::RGBA as i32);
}
constants::IMPLEMENTATION_COLOR_READ_TYPE => {
- if !self.validate_framebuffer_complete() {
- return NullValue();
- } else {
- return Int32Value(constants::UNSIGNED_BYTE as i32);
- }
+ handle_potential_webgl_error!(self, self.validate_framebuffer(), return NullValue());
+ return Int32Value(constants::UNSIGNED_BYTE as i32);
}
constants::COMPRESSED_TEXTURE_FORMATS => {
// FIXME(nox): https://github.com/servo/servo/issues/20594
@@ -1892,80 +1614,71 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
handle_potential_webgl_error!(self, texture.generate_mipmap());
}
- #[allow(unsafe_code)]
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
- unsafe fn BufferData(
+ #[allow(unsafe_code)]
+ fn BufferData(
&self,
- cx: *mut JSContext,
target: u32,
- data: *mut JSObject,
+ data: Option<ArrayBufferViewOrArrayBuffer>,
usage: u32,
- ) -> ErrorResult {
- if data.is_null() {
- return Ok(self.webgl_error(InvalidValue));
- }
+ ) {
+ let data = handle_potential_webgl_error!(self, data.ok_or(InvalidValue), return);
- typedarray!(in(cx) let array_buffer: ArrayBuffer = data);
- let data_vec = match array_buffer {
- Ok(data) => data.to_vec(),
- Err(_) => fallible_array_buffer_view_to_vec(cx, data)?,
- };
+ let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
+ let bound_buffer = handle_potential_webgl_error!(self, bound_buffer.ok_or(InvalidOperation), return);
- let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return Ok(()));
- let bound_buffer = match bound_buffer {
- Some(bound_buffer) => bound_buffer,
- None => return Ok(self.webgl_error(InvalidOperation)),
+ let data = unsafe {
+ // Safe because we don't do anything with JS until the end of the method.
+ match data {
+ ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref data) => data.as_slice(),
+ ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref data) => data.as_slice(),
+ }
};
-
- handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, data_vec, usage));
- Ok(())
+ handle_potential_webgl_error!(self, bound_buffer.buffer_data(data, usage));
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
- fn BufferData_(&self, target: u32, size: i64, usage: u32) -> ErrorResult {
- let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return Ok(()));
- let bound_buffer = match bound_buffer {
- Some(bound_buffer) => bound_buffer,
- None => return Ok(self.webgl_error(InvalidOperation)),
- };
+ fn BufferData_(&self, target: u32, size: i64, usage: u32) {
+ let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
+ let bound_buffer = handle_potential_webgl_error!(self, bound_buffer.ok_or(InvalidOperation), return);
if size < 0 {
- return Ok(self.webgl_error(InvalidValue));
+ return self.webgl_error(InvalidValue);
}
// FIXME: Allocating a buffer based on user-requested size is
// not great, but we don't have a fallible allocation to try.
let data = vec![0u8; size as usize];
- handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, data, usage));
- Ok(())
+ handle_potential_webgl_error!(self, bound_buffer.buffer_data(&data, usage));
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
+ #[allow(unsafe_code)]
fn BufferSubData(&self, target: u32, offset: i64, data: ArrayBufferViewOrArrayBuffer) {
- let data_vec = match data {
- // Typed array is rooted, so we can safely temporarily retrieve its slice
- ArrayBufferViewOrArrayBuffer::ArrayBuffer(inner) => inner.to_vec(),
- ArrayBufferViewOrArrayBuffer::ArrayBufferView(inner) => inner.to_vec(),
- };
-
let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
- let bound_buffer = match bound_buffer {
- Some(bound_buffer) => bound_buffer,
- None => return self.webgl_error(InvalidOperation),
- };
+ let bound_buffer = handle_potential_webgl_error!(self, bound_buffer.ok_or(InvalidOperation), return);
if offset < 0 {
return self.webgl_error(InvalidValue);
}
- if (offset as usize) + data_vec.len() > bound_buffer.capacity() {
+ let data = unsafe {
+ // Safe because we don't do anything with JS until the end of the method.
+ match data {
+ ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref data) => data.as_slice(),
+ ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref data) => data.as_slice(),
+ }
+ };
+ if (offset as u64) + data.len() as u64 > bound_buffer.capacity() as u64 {
return self.webgl_error(InvalidValue);
}
+ let (sender, receiver) = ipc::bytes_channel().unwrap();
self.send_command(WebGLCommand::BufferSubData(
target,
offset as isize,
- data_vec.into(),
+ receiver,
));
+ sender.send(data).unwrap();
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
@@ -1989,9 +1702,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
fn CopyTexImage2D(&self, target: u32, level: i32, internal_format: u32,
x: i32, y: i32, width: i32, height: i32, border: i32) {
- if !self.validate_framebuffer_complete() {
- return;
- }
+ handle_potential_webgl_error!(self, self.validate_framebuffer(), return);
let validator = CommonTexImage2DValidator::new(self, target, level,
internal_format, width,
@@ -2046,9 +1757,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
fn CopyTexSubImage2D(&self, target: u32, level: i32, xoffset: i32, yoffset: i32,
x: i32, y: i32, width: i32, height: i32) {
- if !self.validate_framebuffer_complete() {
- return;
- }
+ handle_potential_webgl_error!(self, self.validate_framebuffer(), return);
// NB: We use a dummy (valid) format and border in order to reuse the
// common validations, but this should have its own validator.
@@ -2089,9 +1798,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11
fn Clear(&self, mask: u32) {
- if !self.validate_framebuffer_complete() {
- return;
- }
+ handle_potential_webgl_error!(self, self.validate_framebuffer(), return);
if mask & !(constants::DEPTH_BUFFER_BIT | constants::STENCIL_BUFFER_BIT | constants::COLOR_BUFFER_BIT) != 0 {
return self.webgl_error(InvalidValue);
}
@@ -2347,12 +2054,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11
fn DrawArrays(&self, mode: u32, first: i32, count: i32) {
- self.draw_arrays_instanced(mode, first, count, 1);
+ handle_potential_webgl_error!(self, self.draw_arrays_instanced(mode, first, count, 1));
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11
fn DrawElements(&self, mode: u32, count: i32, type_: u32, offset: i64) {
- self.draw_elements_instanced(mode, count, type_, offset, 1);
+ handle_potential_webgl_error!(self, self.draw_elements_instanced(mode, count, type_, offset, 1));
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@@ -2757,7 +2464,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
fn IsBuffer(&self, buffer: Option<&WebGLBuffer>) -> bool {
buffer.map_or(false, |buf| {
- self.validate_ownership(buf).is_ok() && buf.target().is_some() && !buf.is_marked_for_deletion()
+ self.validate_ownership(buf).is_ok() && buf.target().is_some() && !buf.is_deleted()
})
}
@@ -2874,9 +2581,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
Some(ref mut data) => (data.get_array_type(), unsafe { data.as_mut_slice() }),
};
- if !self.validate_framebuffer_complete() {
- return;
- }
+ handle_potential_webgl_error!(self, self.validate_framebuffer(), return);
match array_type {
Type::Uint8 => (),
@@ -2957,7 +2662,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
_ => return self.webgl_error(InvalidOperation),
};
- let (sender, receiver) = webgl_channel().unwrap();
+ let (sender, receiver) = ipc::bytes_channel().unwrap();
self.send_command(WebGLCommand::ReadPixels(x, y, width, height, format, pixel_type, sender));
let result = receiver.recv().unwrap();
@@ -3643,7 +3348,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if values.len() < 1 {
- return self.webgl_error(InvalidOperation);
+ // https://github.com/KhronosGroup/WebGL/issues/2700
+ return self.webgl_error(InvalidValue);
}
self.vertex_attrib(indx, values[0], 0f32, 0f32, 1f32);
}
@@ -3660,7 +3366,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if values.len() < 2 {
- return self.webgl_error(InvalidOperation);
+ // https://github.com/KhronosGroup/WebGL/issues/2700
+ return self.webgl_error(InvalidValue);
}
self.vertex_attrib(indx, values[0], values[1], 0f32, 1f32);
}
@@ -3677,7 +3384,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if values.len() < 3 {
- return self.webgl_error(InvalidOperation);
+ // https://github.com/KhronosGroup/WebGL/issues/2700
+ return self.webgl_error(InvalidValue);
}
self.vertex_attrib(indx, values[0], values[1], values[2], 1f32);
}
@@ -3694,7 +3402,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if values.len() < 4 {
- return self.webgl_error(InvalidOperation);
+ // https://github.com/KhronosGroup/WebGL/issues/2700
+ return self.webgl_error(InvalidValue);
}
self.vertex_attrib(indx, values[0], values[1], values[2], values[3]);
}
@@ -3742,7 +3451,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
border: i32,
format: u32,
data_type: u32,
- mut pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
+ pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
) -> ErrorResult {
if !self.extension_manager.is_tex_type_enabled(data_type) {
return Ok(self.webgl_error(InvalidEnum));
@@ -3780,7 +3489,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// initialized to 0 is passed.
let buff = match *pixels {
None => vec![0u8; expected_byte_length as usize],
- Some(ref mut data) => data.to_vec(),
+ Some(ref data) => data.to_vec(),
};
// From the WebGL spec:
@@ -4271,3 +3980,217 @@ impl TextureUnit {
None
}
}
+
+// Remove premultiplied alpha.
+// This is only called when texImage2D is called using a canvas2d source and
+// UNPACK_PREMULTIPLY_ALPHA_WEBGL is disabled. Pixels got from a canvas2D source
+// are always RGBA8 with premultiplied alpha, so we don't have to worry about
+// additional formats as happens in the premultiply_pixels method.
+fn remove_premultiplied_alpha(pixels: &mut [u8]) {
+ for rgba in pixels.chunks_mut(4) {
+ let a = (rgba[3] as f32) / 255.0;
+ rgba[0] = (rgba[0] as f32 / a) as u8;
+ rgba[1] = (rgba[1] as f32 / a) as u8;
+ rgba[2] = (rgba[2] as f32 / a) as u8;
+ }
+}
+
+/// Translates an image in rgba8 (red in the first byte) format to
+/// the format that was requested of TexImage.
+///
+/// From the WebGL 1.0 spec, 5.14.8:
+///
+/// "The source image data is conceptually first converted to
+/// the data type and format specified by the format and type
+/// arguments, and then transferred to the WebGL
+/// implementation. If a packed pixel format is specified
+/// which would imply loss of bits of precision from the image
+/// data, this loss of precision must occur."
+fn rgba8_image_to_tex_image_data(
+ format: TexFormat,
+ data_type: TexDataType,
+ mut pixels: Vec<u8>,
+) -> Vec<u8> {
+ // hint for vector allocation sizing.
+ let pixel_count = pixels.len() / 4;
+
+ match (format, data_type) {
+ (TexFormat::RGBA, TexDataType::UnsignedByte) => pixels,
+ (TexFormat::RGB, TexDataType::UnsignedByte) => {
+ for i in 0..pixel_count {
+ let rgb = {
+ let rgb = &pixels[i * 4..i * 4 + 3];
+ [rgb[0], rgb[1], rgb[2]]
+ };
+ pixels[i * 3..i * 3 + 3].copy_from_slice(&rgb);
+ }
+ pixels.truncate(pixel_count * 3);
+ pixels
+ },
+ (TexFormat::Alpha, TexDataType::UnsignedByte) => {
+ for i in 0..pixel_count {
+ let p = pixels[i * 4 + 3];
+ pixels[i] = p;
+ }
+ pixels.truncate(pixel_count);
+ pixels
+ },
+ (TexFormat::Luminance, TexDataType::UnsignedByte) => {
+ for i in 0..pixel_count {
+ let p = pixels[i * 4];
+ pixels[i] = p;
+ }
+ pixels.truncate(pixel_count);
+ pixels
+ },
+ (TexFormat::LuminanceAlpha, TexDataType::UnsignedByte) => {
+ for i in 0..pixel_count {
+ let (lum, a) = {
+ let rgba = &pixels[i * 4..i * 4 + 4];
+ (rgba[0], rgba[3])
+ };
+ pixels[i * 2] = lum;
+ pixels[i * 2 + 1] = a;
+ }
+ pixels.truncate(pixel_count * 2);
+ pixels
+ },
+ (TexFormat::RGBA, TexDataType::UnsignedShort4444) => {
+ for i in 0..pixel_count {
+ let p = {
+ let rgba = &pixels[i * 4..i * 4 + 4];
+ (rgba[0] as u16 & 0xf0) << 8 |
+ (rgba[1] as u16 & 0xf0) << 4 |
+ (rgba[2] as u16 & 0xf0) |
+ (rgba[3] as u16 & 0xf0) >> 4
+ };
+ NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p);
+ }
+ pixels.truncate(pixel_count * 2);
+ pixels
+ },
+ (TexFormat::RGBA, TexDataType::UnsignedShort5551) => {
+ for i in 0..pixel_count {
+ let p = {
+ let rgba = &pixels[i * 4..i * 4 + 4];
+ (rgba[0] as u16 & 0xf8) << 8 |
+ (rgba[1] as u16 & 0xf8) << 3 |
+ (rgba[2] as u16 & 0xf8) >> 2 |
+ (rgba[3] as u16) >> 7
+ };
+ NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p);
+ }
+ pixels.truncate(pixel_count * 2);
+ pixels
+ },
+ (TexFormat::RGB, TexDataType::UnsignedShort565) => {
+ for i in 0..pixel_count {
+ let p = {
+ let rgb = &pixels[i * 4..i * 4 + 3];
+ (rgb[0] as u16 & 0xf8) << 8 |
+ (rgb[1] as u16 & 0xfc) << 3 |
+ (rgb[2] as u16 & 0xf8) >> 3
+ };
+ NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p);
+ }
+ pixels.truncate(pixel_count * 2);
+ pixels
+ },
+ (TexFormat::RGBA, TexDataType::Float) => {
+ let mut rgbaf32 = Vec::<u8>::with_capacity(pixel_count * 16);
+ for rgba8 in pixels.chunks(4) {
+ rgbaf32.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap();
+ rgbaf32.write_f32::<NativeEndian>(rgba8[1] as f32).unwrap();
+ rgbaf32.write_f32::<NativeEndian>(rgba8[2] as f32).unwrap();
+ rgbaf32.write_f32::<NativeEndian>(rgba8[3] as f32).unwrap();
+ }
+ rgbaf32
+ }
+
+ (TexFormat::RGB, TexDataType::Float) => {
+ let mut rgbf32 = Vec::<u8>::with_capacity(pixel_count * 12);
+ for rgba8 in pixels.chunks(4) {
+ rgbf32.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap();
+ rgbf32.write_f32::<NativeEndian>(rgba8[1] as f32).unwrap();
+ rgbf32.write_f32::<NativeEndian>(rgba8[2] as f32).unwrap();
+ }
+ rgbf32
+ }
+
+ (TexFormat::Alpha, TexDataType::Float) => {
+ for rgba8 in pixels.chunks_mut(4) {
+ let p = rgba8[3] as f32;
+ NativeEndian::write_f32(rgba8, p);
+ }
+ pixels
+ },
+
+ (TexFormat::Luminance, TexDataType::Float) => {
+ for rgba8 in pixels.chunks_mut(4) {
+ let p = rgba8[0] as f32;
+ NativeEndian::write_f32(rgba8, p);
+ }
+ pixels
+ },
+
+ (TexFormat::LuminanceAlpha, TexDataType::Float) => {
+ let mut data = Vec::<u8>::with_capacity(pixel_count * 8);
+ for rgba8 in pixels.chunks(4) {
+ data.write_f32::<NativeEndian>(rgba8[0] as f32).unwrap();
+ data.write_f32::<NativeEndian>(rgba8[3] as f32).unwrap();
+ }
+ data
+ },
+
+ (TexFormat::RGBA, TexDataType::HalfFloat) => {
+ let mut rgbaf16 = Vec::<u8>::with_capacity(pixel_count * 8);
+ for rgba8 in pixels.chunks(4) {
+ rgbaf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[0] as f32).as_bits()).unwrap();
+ rgbaf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[1] as f32).as_bits()).unwrap();
+ rgbaf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[2] as f32).as_bits()).unwrap();
+ rgbaf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[3] as f32).as_bits()).unwrap();
+ }
+ rgbaf16
+ },
+
+ (TexFormat::RGB, TexDataType::HalfFloat) => {
+ let mut rgbf16 = Vec::<u8>::with_capacity(pixel_count * 6);
+ for rgba8 in pixels.chunks(4) {
+ rgbf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[0] as f32).as_bits()).unwrap();
+ rgbf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[1] as f32).as_bits()).unwrap();
+ rgbf16.write_u16::<NativeEndian>(f16::from_f32(rgba8[2] as f32).as_bits()).unwrap();
+ }
+ rgbf16
+ },
+ (TexFormat::Alpha, TexDataType::HalfFloat) => {
+ for i in 0..pixel_count {
+ let p = f16::from_f32(pixels[i * 4 + 3] as f32).as_bits();
+ NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p);
+ }
+ pixels.truncate(pixel_count * 2);
+ pixels
+ },
+ (TexFormat::Luminance, TexDataType::HalfFloat) => {
+ for i in 0..pixel_count {
+ let p = f16::from_f32(pixels[i * 4] as f32).as_bits();
+ NativeEndian::write_u16(&mut pixels[i * 2..i * 2 + 2], p);
+ }
+ pixels.truncate(pixel_count * 2);
+ pixels
+ },
+ (TexFormat::LuminanceAlpha, TexDataType::HalfFloat) => {
+ for rgba8 in pixels.chunks_mut(4) {
+ let lum = f16::from_f32(rgba8[0] as f32).as_bits();
+ let a = f16::from_f32(rgba8[3] as f32).as_bits();
+ NativeEndian::write_u16(&mut rgba8[0..2], lum);
+ NativeEndian::write_u16(&mut rgba8[2..4], a);
+ }
+ pixels
+ },
+
+ // Validation should have ensured that we only hit the
+ // above cases, but we haven't turned the (format, type)
+ // into an enum yet so there's a default case here.
+ _ => unreachable!("Unsupported formats {:?} {:?}", format, data_type)
+ }
+}
diff --git a/components/script/dom/webglvertexarrayobjectoes.rs b/components/script/dom/webglvertexarrayobjectoes.rs
index c717108b2aa..ca13b2833f5 100644
--- a/components/script/dom/webglvertexarrayobjectoes.rs
+++ b/components/script/dom/webglvertexarrayobjectoes.rs
@@ -124,8 +124,15 @@ impl WebGLVertexArrayObjectOES {
}
let context = self.upcast::<WebGLObject>().context();
- let buffer = context.array_buffer().ok_or(WebGLError::InvalidOperation)?;
- buffer.increment_attached_counter();
+ let buffer = context.array_buffer();
+ match buffer {
+ Some(ref buffer) => buffer.increment_attached_counter(),
+ None if offset != 0 => {
+ // https://github.com/KhronosGroup/WebGL/pull/2228
+ return Err(WebGLError::InvalidOperation)
+ },
+ _ => {},
+ }
context.send_command(WebGLCommand::VertexAttribPointer(
index,
size,
@@ -146,7 +153,7 @@ impl WebGLVertexArrayObjectOES {
normalized,
stride: stride as u8,
offset: offset as u32,
- buffer: Some(Dom::from_ref(&*buffer)),
+ buffer: buffer.map(|b| Dom::from_ref(&*b)),
divisor: data.divisor,
};
diff --git a/components/script/dom/webidls/BaseAudioContext.webidl b/components/script/dom/webidls/BaseAudioContext.webidl
index f00ec373667..f8b85007a64 100644
--- a/components/script/dom/webidls/BaseAudioContext.webidl
+++ b/components/script/dom/webidls/BaseAudioContext.webidl
@@ -30,13 +30,13 @@ interface BaseAudioContext : EventTarget {
Promise<AudioBuffer> decodeAudioData(ArrayBuffer audioData,
optional DecodeSuccessCallback successCallback,
optional DecodeErrorCallback errorCallback);
- AudioBufferSourceNode createBufferSource();
+ [Throws] AudioBufferSourceNode createBufferSource();
// ConstantSourceNode createConstantSource();
// ScriptProcessorNode createScriptProcessor(optional unsigned long bufferSize = 0,
// optional unsigned long numberOfInputChannels = 2,
// optional unsigned long numberOfOutputChannels = 2);
// AnalyserNode createAnalyser();
- GainNode createGain();
+ [Throws] GainNode createGain();
// DelayNode createDelay(optional double maxDelayTime = 1);
// BiquadFilterNode createBiquadFilter();
// IIRFilterNode createIIRFilter(sequence<double> feedforward,
@@ -46,9 +46,9 @@ interface BaseAudioContext : EventTarget {
// StereoPannerNode createStereoPanner();
// ConvolverNode createConvolver();
// ChannelSplitterNode createChannelSplitter(optional unsigned long numberOfOutputs = 6);
- // ChannelMergerNode createChannelMerger(optional unsigned long numberOfInputs = 6);
+ [Throws] ChannelMergerNode createChannelMerger(optional unsigned long numberOfInputs = 6);
// DynamicsCompressorNode createDynamicsCompressor();
- OscillatorNode createOscillator();
+ [Throws] OscillatorNode createOscillator();
// PeriodicWave createPeriodicWave(sequence<float> real,
// sequence<float> imag,
// optional PeriodicWaveConstraints constraints);
diff --git a/components/script/dom/webidls/ChannelMergerNode.webidl b/components/script/dom/webidls/ChannelMergerNode.webidl
new file mode 100644
index 00000000000..071da8971a0
--- /dev/null
+++ b/components/script/dom/webidls/ChannelMergerNode.webidl
@@ -0,0 +1,16 @@
+/* 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/. */
+/*
+ * The origin of this IDL file is
+ * https://webaudio.github.io/web-audio-api/#channelmergernode
+ */
+
+dictionary ChannelMergerOptions : AudioNodeOptions {
+ unsigned long numberOfInputs = 6;
+};
+
+[Exposed=Window,
+ Constructor (BaseAudioContext context, optional ChannelMergerOptions options)]
+interface ChannelMergerNode : AudioNode {
+};
diff --git a/components/script/dom/webidls/PannerNode.webidl b/components/script/dom/webidls/PannerNode.webidl
index 18d01f52b11..b1c1cdfb68f 100644
--- a/components/script/dom/webidls/PannerNode.webidl
+++ b/components/script/dom/webidls/PannerNode.webidl
@@ -45,7 +45,7 @@ interface PannerNode : AudioNode {
readonly attribute AudioParam orientationY;
readonly attribute AudioParam orientationZ;
attribute DistanceModelType distanceModel;
- attribute double refDistance;
+ [SetterThrows] attribute double refDistance;
[SetterThrows] attribute double maxDistance;
[SetterThrows] attribute double rolloffFactor;
attribute double coneInnerAngle;
diff --git a/components/script/dom/webidls/WebGL2RenderingContext.webidl b/components/script/dom/webidls/WebGL2RenderingContext.webidl
index b14711d107e..88a2fb273b6 100644
--- a/components/script/dom/webidls/WebGL2RenderingContext.webidl
+++ b/components/script/dom/webidls/WebGL2RenderingContext.webidl
@@ -305,10 +305,7 @@ interface WebGL2RenderingContextBase
/* Buffer objects */
// WebGL1:
// BUG: https://github.com/KhronosGroup/WebGL/issues/2216
- // FIXME(xanewok): https://github.com/servo/servo/issues/20513
- [Throws]
- void bufferData(GLenum target, object? data, GLenum usage);
- [Throws]
+ void bufferData(GLenum target, /*[AllowShared]*/ BufferSource? data, GLenum usage);
void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
void bufferSubData(GLenum target, GLintptr dstByteOffset, /*[AllowShared]*/ BufferSource srcData);
// WebGL2:
diff --git a/components/script/dom/webidls/WebGLRenderingContext.webidl b/components/script/dom/webidls/WebGLRenderingContext.webidl
index d36154c7355..2a5d8cf99d0 100644
--- a/components/script/dom/webidls/WebGLRenderingContext.webidl
+++ b/components/script/dom/webidls/WebGLRenderingContext.webidl
@@ -421,7 +421,8 @@ interface WebGLRenderingContextBase
const GLenum RGB5_A1 = 0x8057;
const GLenum RGB565 = 0x8D62;
const GLenum DEPTH_COMPONENT16 = 0x81A5;
- const GLenum STENCIL_INDEX = 0x1901;
+ // https://github.com/KhronosGroup/WebGL/pull/2371
+ // const GLenum STENCIL_INDEX = 0x1901;
const GLenum STENCIL_INDEX8 = 0x8D48;
const GLenum DEPTH_STENCIL = 0x84F9;
@@ -687,10 +688,7 @@ interface WebGLRenderingContext
{
// BUG: https://github.com/KhronosGroup/WebGL/issues/2216
- // FIXME(xanewok): https://github.com/servo/servo/issues/20513
- [Throws]
- void bufferData(GLenum target, object? data, GLenum usage);
- [Throws]
+ void bufferData(GLenum target, /*[AllowShared]*/ BufferSource? data, GLenum usage);
void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
void bufferSubData(GLenum target, GLintptr offset, /*[AllowShared]*/ BufferSource data);
diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs
index 2de8f97d98e..ac0f14ad436 100644
--- a/components/script/dom/websocket.rs
+++ b/components/script/dom/websocket.rs
@@ -39,8 +39,8 @@ use std::cell::Cell;
use std::ptr;
use std::thread;
use task::{TaskOnce, TaskCanceller};
-use task_source::{TaskSource, TaskSourceName};
-use task_source::networking::NetworkingTaskSource;
+use task_source::TaskSource;
+use task_source::websocket::WebsocketTaskSource;
#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
enum WebSocketRequestState {
@@ -70,7 +70,7 @@ mod close_code {
pub fn close_the_websocket_connection(
address: Trusted<WebSocket>,
- task_source: &NetworkingTaskSource,
+ task_source: &WebsocketTaskSource,
canceller: &TaskCanceller,
code: Option<u16>,
reason: String,
@@ -86,7 +86,7 @@ pub fn close_the_websocket_connection(
pub fn fail_the_websocket_connection(
address: Trusted<WebSocket>,
- task_source: &NetworkingTaskSource,
+ task_source: &WebsocketTaskSource,
canceller: &TaskCanceller,
) {
let close_task = CloseTask {
@@ -199,11 +199,8 @@ impl WebSocket {
};
let _ = global.core_resource_thread().send(CoreResourceMsg::Fetch(request, channels));
- // TODO: use a dedicated task source,
- // https://html.spec.whatwg.org/multipage/#websocket-task-source
- // When making the switch, also update the task_canceller call.
- let task_source = global.networking_task_source();
- let canceller = global.task_canceller(TaskSourceName::Networking);
+ let task_source = global.websocket_task_source();
+ let canceller = global.task_canceller(WebsocketTaskSource::NAME);
thread::spawn(move || {
while let Ok(event) = dom_event_receiver.recv() {
match event {
@@ -268,7 +265,13 @@ impl WebSocket {
let pipeline_id = self.global().pipeline_id();
self.global()
.script_chan()
- .send(CommonScriptMsg::Task(WebSocketEvent, task, Some(pipeline_id)))
+ // TODO: Use a dedicated `websocket-task-source` task source instead.
+ .send(CommonScriptMsg::Task(
+ WebSocketEvent,
+ task,
+ Some(pipeline_id),
+ WebsocketTaskSource::NAME,
+ ))
.unwrap();
}
@@ -401,10 +404,10 @@ impl WebSocketMethods for WebSocket {
// TODO: use a dedicated task source,
// https://html.spec.whatwg.org/multipage/#websocket-task-source
// When making the switch, also update the task_canceller call.
- let task_source = self.global().networking_task_source();
+ let task_source = self.global().websocket_task_source();
fail_the_websocket_connection(address,
&task_source,
- &self.global().task_canceller(TaskSourceName::Networking));
+ &self.global().task_canceller(WebsocketTaskSource::NAME));
}
WebSocketRequestState::Open => {
self.ready_state.set(WebSocketRequestState::Closing);
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index e125aa87fd9..052f121fb2a 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -128,6 +128,7 @@ use task_source::networking::NetworkingTaskSource;
use task_source::performance_timeline::PerformanceTimelineTaskSource;
use task_source::remote_event::RemoteEventTaskSource;
use task_source::user_interaction::UserInteractionTaskSource;
+use task_source::websocket::WebsocketTaskSource;
use time;
use timers::{IsInterval, TimerCallback};
use url::Position;
@@ -186,6 +187,8 @@ pub struct Window {
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,
navigator: MutNullableDom<Navigator>,
#[ignore_malloc_size_of = "Arc"]
image_cache: Arc<ImageCache>,
@@ -376,6 +379,10 @@ impl Window {
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
}
@@ -1089,6 +1096,7 @@ impl WindowMethods for Window {
ParsingMode::DEFAULT,
quirks_mode,
self.css_error_reporter(),
+ None,
);
let media_query_list =
media_queries::MediaList::parse(&context, &mut parser);
@@ -1666,7 +1674,8 @@ impl Window {
let _ = self.script_chan.send(CommonScriptMsg::Task(
ScriptThreadEventCategory::DomEvent,
Box::new(self.task_canceller(TaskSourceName::DOMManipulation).wrap_task(task)),
- self.pipeline_id()
+ self.pipeline_id(),
+ TaskSourceName::DOMManipulation,
));
doc.set_url(url.clone());
return
@@ -1902,6 +1911,7 @@ impl Window {
file_reading_task_source: FileReadingTaskSource,
performance_timeline_task_source: PerformanceTimelineTaskSource,
remote_event_task_source: RemoteEventTaskSource,
+ websocket_task_source: WebsocketTaskSource,
image_cache_chan: Sender<ImageCacheMsg>,
image_cache: Arc<ImageCache>,
resource_threads: ResourceThreads,
@@ -1955,6 +1965,7 @@ impl Window {
file_reading_task_source,
performance_timeline_task_source,
remote_event_task_source,
+ websocket_task_source,
image_cache_chan,
image_cache,
navigator: Default::default(),
@@ -2123,7 +2134,8 @@ impl Window {
let _ = self.script_chan.send(CommonScriptMsg::Task(
ScriptThreadEventCategory::DomEvent,
Box::new(self.task_canceller(TaskSourceName::DOMManipulation).wrap_task(task)),
- self.pipeline_id()
+ self.pipeline_id(),
+ TaskSourceName::DOMManipulation,
));
}
}
diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs
index b3ba42afb2b..653a2fa141c 100644
--- a/components/script/dom/worker.rs
+++ b/components/script/dom/worker.rs
@@ -14,7 +14,7 @@ use dom::bindings::reflector::{DomObject, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::bindings::str::DOMString;
use dom::bindings::structuredclone::StructuredCloneData;
-use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
+use dom::dedicatedworkerglobalscope::{DedicatedWorkerGlobalScope, DedicatedWorkerScriptMsg};
use dom::eventtarget::EventTarget;
use dom::globalscope::GlobalScope;
use dom::messageevent::MessageEvent;
@@ -40,14 +40,14 @@ pub struct Worker {
#[ignore_malloc_size_of = "Defined in std"]
/// Sender to the Receiver associated with the DedicatedWorkerGlobalScope
/// this Worker created.
- sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
+ sender: Sender<DedicatedWorkerScriptMsg>,
#[ignore_malloc_size_of = "Arc"]
closing: Arc<AtomicBool>,
terminated: Cell<bool>,
}
impl Worker {
- fn new_inherited(sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
+ fn new_inherited(sender: Sender<DedicatedWorkerScriptMsg>,
closing: Arc<AtomicBool>) -> Worker {
Worker {
eventtarget: EventTarget::new_inherited(),
@@ -58,7 +58,7 @@ impl Worker {
}
pub fn new(global: &GlobalScope,
- sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
+ sender: Sender<DedicatedWorkerScriptMsg>,
closing: Arc<AtomicBool>) -> DomRoot<Worker> {
reflect_dom_object(Box::new(Worker::new_inherited(sender, closing)),
global,
@@ -148,7 +148,7 @@ impl WorkerMethods for Worker {
// NOTE: step 9 of https://html.spec.whatwg.org/multipage/#dom-messageport-postmessage
// indicates that a nonexistent communication channel should result in a silent error.
- let _ = self.sender.send((address, WorkerScriptMsg::DOMMessage(data)));
+ let _ = self.sender.send(DedicatedWorkerScriptMsg::CommonWorker(address, WorkerScriptMsg::DOMMessage(data)));
Ok(())
}
diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs
index 5415492b0da..ac372c5fe98 100644
--- a/components/script/dom/workerglobalscope.rs
+++ b/components/script/dom/workerglobalscope.rs
@@ -47,6 +47,7 @@ use task_source::file_reading::FileReadingTaskSource;
use task_source::networking::NetworkingTaskSource;
use task_source::performance_timeline::PerformanceTimelineTaskSource;
use task_source::remote_event::RemoteEventTaskSource;
+use task_source::websocket::WebsocketTaskSource;
use time::precise_time_ns;
use timers::{IsInterval, TimerCallback};
@@ -386,6 +387,10 @@ impl WorkerGlobalScope {
RemoteEventTaskSource(self.script_chan(), self.pipeline_id())
}
+ pub fn websocket_task_source(&self) -> WebsocketTaskSource {
+ WebsocketTaskSource(self.script_chan(), self.pipeline_id())
+ }
+
pub fn new_script_pair(&self) -> (Box<ScriptChan + Send>, Box<ScriptPort + Send>) {
let dedicated = self.downcast::<DedicatedWorkerGlobalScope>();
if let Some(dedicated) = dedicated {
@@ -397,7 +402,7 @@ impl WorkerGlobalScope {
pub fn process_event(&self, msg: CommonScriptMsg) {
match msg {
- CommonScriptMsg::Task(_, task, _) => {
+ CommonScriptMsg::Task(_, task, _, _) => {
task.run_box()
},
CommonScriptMsg::CollectReports(reports_chan) => {
@@ -407,8 +412,6 @@ impl WorkerGlobalScope {
reports_chan.send(reports);
},
}
-
- // FIXME(jdm): Should we do a microtask checkpoint here?
}
pub fn handle_fire_timer(&self, timer_id: TimerEventId) {
diff --git a/components/script/dom/worklet.rs b/components/script/dom/worklet.rs
index a2e454507a8..d1b7ba9c44a 100644
--- a/components/script/dom/worklet.rs
+++ b/components/script/dom/worklet.rs
@@ -66,6 +66,7 @@ use style::thread_state::{self, ThreadState};
use swapper::Swapper;
use swapper::swapper;
use task::TaskBox;
+use task_source::TaskSourceName;
use uuid::Uuid;
// Magic numbers
@@ -644,7 +645,14 @@ impl WorkletThread {
where
T: TaskBox + 'static,
{
- let msg = CommonScriptMsg::Task(ScriptThreadEventCategory::WorkletEvent, Box::new(task), None);
+ // NOTE: It's unclear which task source should be used here:
+ // https://drafts.css-houdini.org/worklets/#dom-worklet-addmodule
+ let msg = CommonScriptMsg::Task(
+ ScriptThreadEventCategory::WorkletEvent,
+ Box::new(task),
+ None,
+ TaskSourceName::DOMManipulation,
+ );
let msg = MainThreadScriptMsg::Common(msg);
self.global_init.to_script_thread_sender.send(msg).expect("Worklet thread outlived script thread.");
}