aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/bindings/structuredclone.rs44
-rw-r--r--components/script/dom/bluetooth.rs267
-rw-r--r--components/script/dom/serviceworker.rs48
-rw-r--r--components/script/dom/serviceworkercontainer.rs3
-rw-r--r--components/script/dom/serviceworkerglobalscope.rs43
-rw-r--r--components/script/dom/serviceworkerregistration.rs8
-rw-r--r--components/script/dom/webidls/Bluetooth.webidl17
-rw-r--r--components/script/dom/webidls/DOMTokenList.webidl1
-rw-r--r--components/script/dom/webidls/ServiceWorker.webidl2
-rw-r--r--components/script/dom/worker.rs5
-rw-r--r--components/script/dom/workerglobalscope.rs8
11 files changed, 310 insertions, 136 deletions
diff --git a/components/script/dom/bindings/structuredclone.rs b/components/script/dom/bindings/structuredclone.rs
index f9c4e98f2f9..21963eec172 100644
--- a/components/script/dom/bindings/structuredclone.rs
+++ b/components/script/dom/bindings/structuredclone.rs
@@ -12,11 +12,14 @@ use js::jsapi::{JSContext, JS_ReadStructuredClone, JS_STRUCTURED_CLONE_VERSION};
use js::jsapi::{JS_ClearPendingException, JS_WriteStructuredClone};
use libc::size_t;
use std::ptr;
+use std::slice;
/// A buffer for a structured clone.
-pub struct StructuredCloneData {
- data: *mut u64,
- nbytes: size_t,
+pub enum StructuredCloneData {
+ /// A non-serializable (default) variant
+ Struct(*mut u64, size_t),
+ /// A variant that can be serialized
+ Vector(Vec<u8>)
}
impl StructuredCloneData {
@@ -39,26 +42,47 @@ impl StructuredCloneData {
}
return Err(Error::DataClone);
}
- Ok(StructuredCloneData {
- data: data,
- nbytes: nbytes,
- })
+ Ok(StructuredCloneData::Struct(data, nbytes))
+ }
+
+ /// Converts a StructuredCloneData to Vec<u8> for inter-thread sharing
+ pub fn move_to_arraybuffer(self) -> Vec<u8> {
+ match self {
+ StructuredCloneData::Struct(data, nbytes) => {
+ unsafe {
+ slice::from_raw_parts(data as *mut u8, nbytes).to_vec()
+ }
+ }
+ StructuredCloneData::Vector(msg) => msg
+ }
}
/// Reads a structured clone.
///
/// Panics if `JS_ReadStructuredClone` fails.
- pub fn read(self, global: GlobalRef, rval: MutableHandleValue) {
+ fn read_clone(global: GlobalRef, data: *mut u64, nbytes: size_t, rval: MutableHandleValue) {
unsafe {
assert!(JS_ReadStructuredClone(global.get_cx(),
- self.data,
- self.nbytes,
+ data,
+ nbytes,
JS_STRUCTURED_CLONE_VERSION,
rval,
ptr::null(),
ptr::null_mut()));
}
}
+
+ /// Thunk for the actual `read_clone` method. Resolves proper variant for read_clone.
+ pub fn read(self, global: GlobalRef, rval: MutableHandleValue) {
+ match self {
+ StructuredCloneData::Vector(mut vec_msg) => {
+ let nbytes = vec_msg.len();
+ let data = vec_msg.as_mut_ptr() as *mut u64;
+ StructuredCloneData::read_clone(global, data, nbytes, rval);
+ }
+ StructuredCloneData::Struct(data, nbytes) => StructuredCloneData::read_clone(global, data, nbytes, rval)
+ }
+ }
}
unsafe impl Send for StructuredCloneData {}
diff --git a/components/script/dom/bluetooth.rs b/components/script/dom/bluetooth.rs
index 6540f6c971f..2940a211bf3 100644
--- a/components/script/dom/bluetooth.rs
+++ b/components/script/dom/bluetooth.rs
@@ -4,8 +4,7 @@
use bluetooth_blacklist::{Blacklist, uuid_is_blacklisted};
use core::clone::Clone;
-use dom::bindings::codegen::Bindings::BluetoothBinding;
-use dom::bindings::codegen::Bindings::BluetoothBinding::{BluetoothMethods, BluetoothScanFilter};
+use dom::bindings::codegen::Bindings::BluetoothBinding::{self, BluetoothMethods, BluetoothRequestDeviceFilter};
use dom::bindings::codegen::Bindings::BluetoothBinding::RequestDeviceOptions;
use dom::bindings::error::Error::{self, Security, Type};
use dom::bindings::error::Fallible;
@@ -15,13 +14,13 @@ use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::bluetoothadvertisingdata::BluetoothAdvertisingData;
use dom::bluetoothdevice::BluetoothDevice;
-use dom::bluetoothuuid::BluetoothUUID;
+use dom::bluetoothuuid::{BluetoothServiceUUID, BluetoothUUID};
use ipc_channel::ipc::{self, IpcSender};
use net_traits::bluetooth_scanfilter::{BluetoothScanfilter, BluetoothScanfilterSequence};
use net_traits::bluetooth_scanfilter::{RequestDeviceoptions, ServiceUUIDSequence};
use net_traits::bluetooth_thread::{BluetoothError, BluetoothMethodMsg};
-const FILTER_EMPTY_ERROR: &'static str = "'filters' member must be non - empty to find any devices.";
+const FILTER_EMPTY_ERROR: &'static str = "'filters' member, if present, must be nonempty to find any devices.";
const FILTER_ERROR: &'static str = "A filter must restrict the devices in some way.";
const FILTER_NAME_TOO_LONG_ERROR: &'static str = "A 'name' or 'namePrefix' can't be longer then 29 bytes.";
// 248 is the maximum number of UTF-8 code units in a Bluetooth Device Name.
@@ -31,9 +30,11 @@ const MAX_DEVICE_NAME_LENGTH: usize = 248;
// The length and identifier of the length field take 2 bytes.
// That leaves 29 bytes for the name.
const MAX_FILTER_NAME_LENGTH: usize = 29;
-const NAME_PREFIX_ERROR: &'static str = "'namePrefix', if present, must be non - empty.";
+const NAME_PREFIX_ERROR: &'static str = "'namePrefix', if present, must be nonempty.";
const NAME_TOO_LONG_ERROR: &'static str = "A device name can't be longer than 248 bytes.";
const SERVICE_ERROR: &'static str = "'services', if present, must contain at least one service.";
+const OPTIONS_ERROR: &'static str = "Fields of 'options' conflict with each other.
+ Either 'acceptAllDevices' member must be true, or 'filters' member must be set to a value.";
// https://webbluetoothcg.github.io/web-bluetooth/#bluetooth
#[dom_struct]
@@ -59,80 +60,196 @@ impl Bluetooth {
let global_ref = global_root.r();
global_ref.as_window().bluetooth_thread()
}
-}
-fn canonicalize_filter(filter: &BluetoothScanFilter, global: GlobalRef) -> Fallible<BluetoothScanfilter> {
- if filter.services.is_none() && filter.name.is_none() && filter.namePrefix.is_none() {
- return Err(Type(FILTER_ERROR.to_owned()));
- }
+ // https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
+ fn request_bluetooth_devices(&self,
+ filters: &Option<Vec<BluetoothRequestDeviceFilter>>,
+ optional_services: &Option<Vec<BluetoothServiceUUID>>)
+ -> Fallible<Root<BluetoothDevice>> {
+ // TODO: Step 1: Triggered by user activation.
- let mut services_vec = vec!();
- if let Some(ref services) = filter.services {
- if services.is_empty() {
- return Err(Type(SERVICE_ERROR.to_owned()));
- }
- for service in services {
- let uuid = try!(BluetoothUUID::GetService(global, service.clone())).to_string();
- if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
- return Err(Security)
- }
- services_vec.push(uuid);
- }
- }
+ // Step 2.
+ let option = try!(convert_request_device_options(self.global().r(), filters, optional_services));
- let mut name = String::new();
- if let Some(ref filter_name) = filter.name {
- //NOTE: DOMString::len() gives back the size in bytes
- if filter_name.len() > MAX_DEVICE_NAME_LENGTH {
- return Err(Type(NAME_TOO_LONG_ERROR.to_owned()));
- }
- if filter_name.len() > MAX_FILTER_NAME_LENGTH {
- return Err(Type(FILTER_NAME_TOO_LONG_ERROR.to_owned()));
- }
- name = filter_name.to_string();
- }
+ // TODO: Step 3-5: Implement the permission API.
- let mut name_prefix = String::new();
- if let Some(ref filter_name_prefix) = filter.namePrefix {
- if filter_name_prefix.is_empty() {
- return Err(Type(NAME_PREFIX_ERROR.to_owned()));
- }
- if filter_name_prefix.len() > MAX_DEVICE_NAME_LENGTH {
- return Err(Type(NAME_TOO_LONG_ERROR.to_owned()));
- }
- if filter_name_prefix.len() > MAX_FILTER_NAME_LENGTH {
- return Err(Type(FILTER_NAME_TOO_LONG_ERROR.to_owned()));
+ // Note: Steps 6-8 are implemented in
+ // components/net/bluetooth_thread.rs in request_device function.
+ let (sender, receiver) = ipc::channel().unwrap();
+ self.get_bluetooth_thread().send(BluetoothMethodMsg::RequestDevice(option, sender)).unwrap();
+ let device = receiver.recv().unwrap();
+
+ // TODO: Step 9-10: Implement the permission API.
+
+ // Step 11: This step is optional.
+
+ // Step 12-13.
+ match device {
+ Ok(device) => {
+ let ad_data = BluetoothAdvertisingData::new(self.global().r(),
+ device.appearance,
+ device.tx_power,
+ device.rssi);
+ Ok(BluetoothDevice::new(self.global().r(),
+ DOMString::from(device.id),
+ device.name.map(DOMString::from),
+ &ad_data))
+ },
+ Err(error) => {
+ Err(Error::from(error))
+ },
}
- name_prefix = filter_name_prefix.to_string();
- }
- Ok(BluetoothScanfilter::new(name, name_prefix, services_vec))
+ }
}
-fn convert_request_device_options(options: &RequestDeviceOptions,
- global: GlobalRef)
+// https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
+fn convert_request_device_options(global: GlobalRef,
+ filters: &Option<Vec<BluetoothRequestDeviceFilter>>,
+ optional_services: &Option<Vec<BluetoothServiceUUID>>)
-> Fallible<RequestDeviceoptions> {
- if options.filters.is_empty() {
- return Err(Type(FILTER_EMPTY_ERROR.to_owned()));
- }
+ // Step 2.2: There is no requiredServiceUUIDS, we scan for all devices.
+ let mut uuid_filters = vec!();
+
+ if let &Some(ref filters) = filters {
+ // Step 2.1.
+ if filters.is_empty() {
+ return Err(Type(FILTER_EMPTY_ERROR.to_owned()));
+ }
+
+ // Step 2.3: There is no requiredServiceUUIDS, we scan for all devices.
- let mut filters = vec!();
- for filter in &options.filters {
- filters.push(try!(canonicalize_filter(&filter, global)));
+ // Step 2.4.
+ for filter in filters {
+ // Step 2.4.8.
+ uuid_filters.push(try!(canonicalize_filter(&filter, global)));
+ }
}
- let mut optional_services = vec!();
- if let Some(ref opt_services) = options.optionalServices {
+ let mut optional_services_uuids = vec!();
+ if let &Some(ref opt_services) = optional_services {
for opt_service in opt_services {
+ // Step 2.5 - 2.6.
let uuid = try!(BluetoothUUID::GetService(global, opt_service.clone())).to_string();
+
+ // Step 2.7.
+ // Note: What we are doing here is adding the not blacklisted UUIDs to the result vector,
+ // insted of removing them from an already filled vector.
if !uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
- optional_services.push(uuid);
+ optional_services_uuids.push(uuid);
}
}
}
- Ok(RequestDeviceoptions::new(BluetoothScanfilterSequence::new(filters),
- ServiceUUIDSequence::new(optional_services)))
+ Ok(RequestDeviceoptions::new(BluetoothScanfilterSequence::new(uuid_filters),
+ ServiceUUIDSequence::new(optional_services_uuids)))
+}
+
+// https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
+fn canonicalize_filter(filter: &BluetoothRequestDeviceFilter, global: GlobalRef) -> Fallible<BluetoothScanfilter> {
+ // Step 2.4.1.
+ if filter.services.is_none() &&
+ filter.name.is_none() &&
+ filter.namePrefix.is_none() &&
+ filter.manufacturerId.is_none() &&
+ filter.serviceDataUUID.is_none() {
+ return Err(Type(FILTER_ERROR.to_owned()));
+ }
+
+ // Step 2.4.2: There is no empty canonicalizedFilter member,
+ // we create a BluetoothScanfilter instance at the end of the function.
+
+ // Step 2.4.3.
+ let services_vec = match filter.services {
+ Some(ref services) => {
+ // Step 2.4.3.1.
+ if services.is_empty() {
+ return Err(Type(SERVICE_ERROR.to_owned()));
+ }
+
+ let mut services_vec = vec!();
+
+ for service in services {
+ // Step 2.4.3.2 - 2.4.3.3.
+ let uuid = try!(BluetoothUUID::GetService(global, service.clone())).to_string();
+
+ // Step 2.4.3.4.
+ if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
+ return Err(Security)
+ }
+
+ services_vec.push(uuid);
+ }
+ // Step 2.4.3.5.
+ services_vec
+ // Step 2.4.3.6: There is no requiredServiceUUIDS, we scan for all devices.
+ },
+ None => vec!(),
+ };
+
+ // Step 2.4.4.
+ let name = match filter.name {
+ Some(ref name) => {
+ // Step 2.4.4.1.
+ // Note: DOMString::len() gives back the size in bytes.
+ if name.len() > MAX_DEVICE_NAME_LENGTH {
+ return Err(Type(NAME_TOO_LONG_ERROR.to_owned()));
+ }
+ if name.len() > MAX_FILTER_NAME_LENGTH {
+ return Err(Type(FILTER_NAME_TOO_LONG_ERROR.to_owned()));
+ }
+
+ // Step 2.4.4.2.
+ name.to_string()
+ },
+ None => String::new(),
+ };
+
+ // Step 2.4.5.
+ let name_prefix = match filter.namePrefix {
+ Some(ref name_prefix) => {
+ // Step 2.4.5.1.
+ if name_prefix.is_empty() {
+ return Err(Type(NAME_PREFIX_ERROR.to_owned()));
+ }
+ if name_prefix.len() > MAX_DEVICE_NAME_LENGTH {
+ return Err(Type(NAME_TOO_LONG_ERROR.to_owned()));
+ }
+ if name_prefix.len() > MAX_FILTER_NAME_LENGTH {
+ return Err(Type(FILTER_NAME_TOO_LONG_ERROR.to_owned()));
+ }
+
+ // Step 2.4.5.2.
+ name_prefix.to_string()
+ },
+ None => String::new(),
+ };
+
+ // Step 2.4.6.
+ let manufacturer_id = filter.manufacturerId;
+
+ // Step 2.4.7.
+ let service_data_uuid = match filter.serviceDataUUID {
+ Some(ref service_data_uuid) => {
+ // Step 2.4.7.1 - 2.4.7.2.
+ let uuid = try!(BluetoothUUID::GetService(global, service_data_uuid.clone())).to_string();
+
+ // Step 2.4.7.3.
+ if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
+ return Err(Security)
+ }
+
+ // Step 2.4.7.4.
+ uuid
+ },
+ None => String::new(),
+ };
+
+ Ok(BluetoothScanfilter::new(name,
+ name_prefix,
+ services_vec,
+ manufacturer_id,
+ service_data_uuid))
}
impl From<BluetoothError> for Error {
@@ -150,24 +267,18 @@ impl From<BluetoothError> for Error {
impl BluetoothMethods for Bluetooth {
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
fn RequestDevice(&self, option: &RequestDeviceOptions) -> Fallible<Root<BluetoothDevice>> {
- let (sender, receiver) = ipc::channel().unwrap();
- let option = try!(convert_request_device_options(option, self.global().r()));
- self.get_bluetooth_thread().send(BluetoothMethodMsg::RequestDevice(option, sender)).unwrap();
- let device = receiver.recv().unwrap();
- match device {
- Ok(device) => {
- let ad_data = BluetoothAdvertisingData::new(self.global().r(),
- device.appearance,
- device.tx_power,
- device.rssi);
- Ok(BluetoothDevice::new(self.global().r(),
- DOMString::from(device.id),
- device.name.map(DOMString::from),
- &ad_data))
- },
- Err(error) => {
- Err(Error::from(error))
- },
+ // Step 1.
+ // TODO(#4282): Reject promise.
+ if (option.filters.is_some() && option.acceptAllDevices) ||
+ (option.filters.is_none() && !option.acceptAllDevices) {
+ return Err(Type(OPTIONS_ERROR.to_owned()));
}
+ // Step 2.
+ if !option.acceptAllDevices {
+ return self.request_bluetooth_devices(&option.filters, &option.optionalServices);
+ }
+
+ self.request_bluetooth_devices(&None, &option.optionalServices)
+ // TODO(#4282): Step 3-5: Reject and resolve promise.
}
}
diff --git a/components/script/dom/serviceworker.rs b/components/script/dom/serviceworker.rs
index 2b79be43dc8..9c37d73bd9e 100644
--- a/components/script/dom/serviceworker.rs
+++ b/components/script/dom/serviceworker.rs
@@ -2,20 +2,23 @@
* 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::abstractworker::{SimpleWorkerErrorHandler, WorkerScriptMsg};
+use dom::abstractworker::SimpleWorkerErrorHandler;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::ServiceWorkerBinding::{ServiceWorkerMethods, ServiceWorkerState, Wrap};
+use dom::bindings::error::{ErrorResult, Error};
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::bindings::refcounted::Trusted;
-use dom::bindings::reflector::reflect_dom_object;
+use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::str::USVString;
+use dom::bindings::structuredclone::StructuredCloneData;
use dom::eventtarget::EventTarget;
+use js::jsapi::{HandleValue, JSContext};
use script_thread::Runnable;
+use script_traits::{ScriptMsg, DOMMessage};
use std::cell::Cell;
-use std::sync::mpsc::Sender;
use url::Url;
pub type TrustedServiceWorkerAddress = Trusted<ServiceWorker>;
@@ -24,28 +27,31 @@ pub type TrustedServiceWorkerAddress = Trusted<ServiceWorker>;
pub struct ServiceWorker {
eventtarget: EventTarget,
script_url: DOMRefCell<String>,
+ scope_url: Url,
state: Cell<ServiceWorkerState>,
- #[ignore_heap_size_of = "Defined in std"]
- sender: Option<Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>>,
skip_waiting: Cell<bool>
}
impl ServiceWorker {
fn new_inherited(script_url: &str,
- skip_waiting: bool) -> ServiceWorker {
+ skip_waiting: bool,
+ scope_url: Url) -> ServiceWorker {
ServiceWorker {
eventtarget: EventTarget::new_inherited(),
- sender: None,
script_url: DOMRefCell::new(String::from(script_url)),
state: Cell::new(ServiceWorkerState::Installing),
+ scope_url: scope_url,
skip_waiting: Cell::new(skip_waiting)
}
}
- pub fn new(global: GlobalRef,
- script_url: &str,
+ pub fn install_serviceworker(global: GlobalRef,
+ script_url: Url,
+ scope_url: Url,
skip_waiting: bool) -> Root<ServiceWorker> {
- reflect_dom_object(box ServiceWorker::new_inherited(script_url, skip_waiting), global, Wrap)
+ reflect_dom_object(box ServiceWorker::new_inherited(script_url.as_str(),
+ skip_waiting,
+ scope_url), global, Wrap)
}
pub fn dispatch_simple_error(address: TrustedServiceWorkerAddress) {
@@ -61,14 +67,6 @@ impl ServiceWorker {
pub fn get_script_url(&self) -> Url {
Url::parse(&self.script_url.borrow().clone()).unwrap()
}
-
- pub fn install_serviceworker(global: GlobalRef,
- script_url: Url,
- skip_waiting: bool) -> Root<ServiceWorker> {
- ServiceWorker::new(global,
- script_url.as_str(),
- skip_waiting)
- }
}
impl ServiceWorkerMethods for ServiceWorker {
@@ -82,6 +80,20 @@ impl ServiceWorkerMethods for ServiceWorker {
USVString(self.script_url.borrow().clone())
}
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-postmessage
+ fn PostMessage(&self, cx: *mut JSContext, message: HandleValue) -> ErrorResult {
+ // Step 1
+ if let ServiceWorkerState::Redundant = self.state.get() {
+ return Err(Error::InvalidState);
+ }
+ // Step 7
+ let data = try!(StructuredCloneData::write(cx, message));
+ let msg_vec = DOMMessage(data.move_to_arraybuffer());
+ let _ = self.global().r().constellation_chan().send(ScriptMsg::ForwardDOMMessage(msg_vec,
+ self.scope_url.clone()));
+ Ok(())
+ }
+
// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-container-onerror-attribute
event_handler!(error, GetOnerror, SetOnerror);
diff --git a/components/script/dom/serviceworkercontainer.rs b/components/script/dom/serviceworkercontainer.rs
index d6379c30183..73e19690e2e 100644
--- a/components/script/dom/serviceworkercontainer.rs
+++ b/components/script/dom/serviceworkercontainer.rs
@@ -95,10 +95,9 @@ impl ServiceWorkerContainerMethods for ServiceWorkerContainer {
return Err(Error::Type("Scope URL contains forbidden characters".to_owned()));
}
- let scope_str = scope.as_str().to_owned();
let worker_registration = ServiceWorkerRegistration::new(self.global().r(),
script_url,
- scope_str.clone(),
+ scope.clone(),
self);
ScriptThread::set_registration(scope, &*worker_registration, self.global().r().pipeline_id());
Ok(worker_registration)
diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs
index 16d5348b6e5..f473c6cadb2 100644
--- a/components/script/dom/serviceworkerglobalscope.rs
+++ b/components/script/dom/serviceworkerglobalscope.rs
@@ -5,7 +5,6 @@
use devtools;
use devtools_traits::DevtoolScriptControlMsg;
use dom::abstractworker::WorkerScriptMsg;
-use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding;
use dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding::ServiceWorkerGlobalScopeMethods;
@@ -16,7 +15,6 @@ use dom::bindings::reflector::Reflectable;
use dom::bindings::str::DOMString;
use dom::eventtarget::EventTarget;
use dom::messageevent::MessageEvent;
-use dom::serviceworker::TrustedServiceWorkerAddress;
use dom::workerglobalscope::WorkerGlobalScope;
use ipc_channel::ipc::{self, IpcSender, IpcReceiver};
use ipc_channel::router::ROUTER;
@@ -26,13 +24,12 @@ use js::rust::Runtime;
use msg::constellation_msg::PipelineId;
use net_traits::{LoadContext, load_whole_resource, IpcSend, CustomResponseMediator};
use rand::random;
-use script_runtime::{CommonScriptMsg, StackRootTLS, get_reports, new_rt_and_cx};
+use script_runtime::{CommonScriptMsg, StackRootTLS, get_reports, new_rt_and_cx, ScriptChan};
use script_traits::{TimerEvent, WorkerGlobalScopeInit, ScopeThings, ServiceWorkerMsg};
use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel};
use std::thread;
use std::time::Duration;
-use style::thread_state;
-use style::thread_state::{IN_WORKER, SCRIPT};
+use style::thread_state::{self, IN_WORKER, SCRIPT};
use url::Url;
use util::prefs::PREFS;
use util::thread::spawn_named;
@@ -48,7 +45,26 @@ pub enum ServiceWorkerScriptMsg {
pub enum MixedMessage {
FromServiceWorker(ServiceWorkerScriptMsg),
FromDevtools(DevtoolScriptControlMsg),
- FromTimeoutThread(()),
+ FromTimeoutThread(())
+}
+
+#[derive(JSTraceable, Clone)]
+pub struct ServiceWorkerChan {
+ pub sender: Sender<ServiceWorkerScriptMsg>
+}
+
+impl ScriptChan for ServiceWorkerChan {
+ fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
+ self.sender
+ .send(ServiceWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(msg)))
+ .map_err(|_| ())
+ }
+
+ fn clone(&self) -> Box<ScriptChan + Send> {
+ box ServiceWorkerChan {
+ sender: self.sender.clone(),
+ }
+ }
}
#[dom_struct]
@@ -61,12 +77,9 @@ pub struct ServiceWorkerGlobalScope {
own_sender: Sender<ServiceWorkerScriptMsg>,
#[ignore_heap_size_of = "Defined in std"]
timer_event_port: Receiver<()>,
- #[ignore_heap_size_of = "Trusted<T> has unclear ownership like JS<T>"]
- worker: DOMRefCell<Option<TrustedServiceWorkerAddress>>,
#[ignore_heap_size_of = "Defined in std"]
swmanager_sender: IpcSender<ServiceWorkerMsg>,
- #[ignore_heap_size_of = "Defined in std"]
- scope_url: Url
+ scope_url: Url,
}
impl ServiceWorkerGlobalScope {
@@ -93,7 +106,6 @@ impl ServiceWorkerGlobalScope {
receiver: receiver,
timer_event_port: timer_event_port,
own_sender: own_sender,
- worker: DOMRefCell::new(None),
swmanager_sender: swmanager_sender,
scope_url: scope_url
}
@@ -228,8 +240,7 @@ impl ServiceWorkerGlobalScope {
CommonWorker(WorkerScriptMsg::DOMMessage(data)) => {
let scope = self.upcast::<WorkerGlobalScope>();
let target = self.upcast();
- let _ac = JSAutoCompartment::new(scope.get_cx(),
- scope.reflector().get_jsobject().get());
+ let _ac = JSAutoCompartment::new(scope.get_cx(), scope.reflector().get_jsobject().get());
rooted!(in(scope.get_cx()) let mut message = UndefinedValue());
data.read(GlobalRef::Worker(scope), message.handle_mut());
MessageEvent::dispatch_jsval(target, GlobalRef::Worker(scope), message.handle());
@@ -292,6 +303,12 @@ impl ServiceWorkerGlobalScope {
pub fn process_event(&self, msg: CommonScriptMsg) {
self.handle_script_event(ServiceWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(msg)));
}
+
+ pub fn script_chan(&self) -> Box<ScriptChan + Send> {
+ box ServiceWorkerChan {
+ sender: self.own_sender.clone()
+ }
+ }
}
#[allow(unsafe_code)]
diff --git a/components/script/dom/serviceworkerregistration.rs b/components/script/dom/serviceworkerregistration.rs
index ccf238dde8a..d246dc4423b 100644
--- a/components/script/dom/serviceworkerregistration.rs
+++ b/components/script/dom/serviceworkerregistration.rs
@@ -25,21 +25,21 @@ pub struct ServiceWorkerRegistration {
}
impl ServiceWorkerRegistration {
- fn new_inherited(active_sw: &ServiceWorker, scope: String) -> ServiceWorkerRegistration {
+ fn new_inherited(active_sw: &ServiceWorker, scope: Url) -> ServiceWorkerRegistration {
ServiceWorkerRegistration {
eventtarget: EventTarget::new_inherited(),
active: Some(JS::from_ref(active_sw)),
installing: None,
waiting: None,
- scope: scope,
+ scope: scope.as_str().to_owned(),
}
}
#[allow(unrooted_must_root)]
pub fn new(global: GlobalRef,
script_url: Url,
- scope: String,
+ scope: Url,
container: &Controllable) -> Root<ServiceWorkerRegistration> {
- let active_worker = ServiceWorker::install_serviceworker(global, script_url.clone(), true);
+ let active_worker = ServiceWorker::install_serviceworker(global, script_url.clone(), scope.clone(), true);
active_worker.set_transition_state(ServiceWorkerState::Installed);
container.set_controller(&*active_worker.clone());
reflect_dom_object(box ServiceWorkerRegistration::new_inherited(&*active_worker, scope), global, Wrap)
diff --git a/components/script/dom/webidls/Bluetooth.webidl b/components/script/dom/webidls/Bluetooth.webidl
index 63cea97ca19..6c575db150c 100644
--- a/components/script/dom/webidls/Bluetooth.webidl
+++ b/components/script/dom/webidls/Bluetooth.webidl
@@ -4,24 +4,31 @@
// https://webbluetoothcg.github.io/web-bluetooth/#bluetooth
-dictionary BluetoothScanFilter {
+dictionary BluetoothRequestDeviceFilter {
sequence<BluetoothServiceUUID> services;
DOMString name;
DOMString namePrefix;
+ unsigned short manufacturerId;
+ BluetoothServiceUUID serviceDataUUID;
};
dictionary RequestDeviceOptions {
- required sequence<BluetoothScanFilter> filters;
+ sequence<BluetoothRequestDeviceFilter> filters;
sequence<BluetoothServiceUUID> optionalServices /*= []*/;
+ boolean acceptAllDevices = false;
};
[Pref="dom.bluetooth.enabled", Exposed=(Window,Worker)]
interface Bluetooth {
- // Promise<BluetoothDevice> requestDevice(RequestDeviceOptions options);
- [Throws]
- BluetoothDevice requestDevice(RequestDeviceOptions options);
+// [SecureContext]
+// readonly attribute BluetoothDevice? referringDevice;
+// [SecureContext]
+// Promise<BluetoothDevice> requestDevice(RequestDeviceOptions options);
+ [Throws]
+ BluetoothDevice requestDevice(optional RequestDeviceOptions options);
};
// Bluetooth implements EventTarget;
+// Bluetooth implements BluetoothDeviceEventHandlers;
// Bluetooth implements CharacteristicEventHandlers;
// Bluetooth implements ServiceEventHandlers;
diff --git a/components/script/dom/webidls/DOMTokenList.webidl b/components/script/dom/webidls/DOMTokenList.webidl
index 7285ac687e1..11bdbda8570 100644
--- a/components/script/dom/webidls/DOMTokenList.webidl
+++ b/components/script/dom/webidls/DOMTokenList.webidl
@@ -25,4 +25,5 @@ interface DOMTokenList {
attribute DOMString value;
stringifier;
+ iterable<DOMString?>;
};
diff --git a/components/script/dom/webidls/ServiceWorker.webidl b/components/script/dom/webidls/ServiceWorker.webidl
index efea6603c3f..0d0855f4239 100644
--- a/components/script/dom/webidls/ServiceWorker.webidl
+++ b/components/script/dom/webidls/ServiceWorker.webidl
@@ -7,7 +7,7 @@
interface ServiceWorker : EventTarget {
readonly attribute USVString scriptURL;
readonly attribute ServiceWorkerState state;
- //[Throws] void postMessage(any message/*, optional sequence<Transferable> transfer*/);
+ [Throws] void postMessage(any message/*, optional sequence<Transferable> transfer*/);
// event
attribute EventHandler onstatechange;
diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs
index 9438569a5d1..1df110a12e5 100644
--- a/components/script/dom/worker.rs
+++ b/components/script/dom/worker.rs
@@ -140,6 +140,7 @@ impl Worker {
worker.upcast().fire_simple_event("error");
}
+ #[allow(unsafe_code)]
fn dispatch_error(&self, error_info: ErrorInfo) {
let global = self.global();
let event = ErrorEvent::new(global.r(),
@@ -150,14 +151,14 @@ impl Worker {
error_info.filename.as_str().into(),
error_info.lineno,
error_info.column,
- NullHandleValue);
+ unsafe { NullHandleValue });
let handled = !event.upcast::<Event>().fire(self.upcast::<EventTarget>());
if handled {
return;
}
- global.r().report_an_error(error_info, NullHandleValue);
+ global.r().report_an_error(error_info, unsafe { NullHandleValue });
}
}
diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs
index 95e9bb13106..bb9a9c3f4ab 100644
--- a/components/script/dom/workerglobalscope.rs
+++ b/components/script/dom/workerglobalscope.rs
@@ -397,12 +397,14 @@ impl WorkerGlobalScope {
}
pub fn script_chan(&self) -> Box<ScriptChan + Send> {
- let dedicated =
- self.downcast::<DedicatedWorkerGlobalScope>();
+ let dedicated = self.downcast::<DedicatedWorkerGlobalScope>();
+ let service_worker = self.downcast::<ServiceWorkerGlobalScope>();
if let Some(dedicated) = dedicated {
return dedicated.script_chan();
+ } else if let Some(service_worker) = service_worker {
+ return service_worker.script_chan();
} else {
- panic!("need to implement a sender for SharedWorker/ServiceWorker")
+ panic!("need to implement a sender for SharedWorker")
}
}