mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
continue messageport, transferable, postmessage options
This commit is contained in:
parent
c3b17c1201
commit
2f8932a6a1
100 changed files with 2456 additions and 1171 deletions
|
@ -3,393 +3,343 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
||||
use crate::dom::bindings::codegen::Bindings::MessagePortBinding::{MessagePortMethods, Wrap};
|
||||
use crate::dom::bindings::conversions::{ToJSValConvertible, root_from_object};
|
||||
use crate::dom::bindings::codegen::Bindings::MessagePortBinding::{
|
||||
MessagePortMethods, PostMessageOptions, Wrap,
|
||||
};
|
||||
use crate::dom::bindings::conversions::root_from_object;
|
||||
use crate::dom::bindings::error::{Error, ErrorResult};
|
||||
use crate::dom::bindings::inheritance::{Castable, HasParent};
|
||||
use crate::dom::bindings::refcounted::Trusted;
|
||||
use crate::dom::bindings::reflector::{DomObject, reflect_dom_object};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::structuredclone::StructuredCloneData;
|
||||
use crate::dom::bindings::trace::JSTraceable;
|
||||
use crate::dom::bindings::structuredclone::{self, StructuredDataHolder};
|
||||
use crate::dom::bindings::trace::RootedTraceableBox;
|
||||
use crate::dom::bindings::transferable::Transferable;
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::messageevent::MessageEvent;
|
||||
use crate::task_source::TaskSource;
|
||||
use crate::task_source::port_message::PortMessageQueue;
|
||||
use js::jsapi::{JSContext, JSStructuredCloneReader, JSObject, JSTracer, MutableHandleObject};
|
||||
use js::jsval::UndefinedValue;
|
||||
use js::rust::{CustomAutoRooterGuard, HandleValue};
|
||||
use servo_remutex::ReentrantMutex;
|
||||
use crate::script_runtime::JSContext as SafeJSContext;
|
||||
use dom_struct::dom_struct;
|
||||
use js::jsapi::Heap;
|
||||
use js::jsapi::{JSObject, MutableHandleObject};
|
||||
use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue};
|
||||
use msg::constellation_msg::{MessagePortId, MessagePortIndex, PipelineNamespaceId};
|
||||
use script_traits::PortMessageTask;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::VecDeque;
|
||||
use std::mem;
|
||||
use std::os::raw;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::num::NonZeroU32;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
// FIXME: This is wrong, we need to figure out a better way of collecting message port objects per transfer
|
||||
thread_local! {
|
||||
pub static TRANSFERRED_MESSAGE_PORTS: RefCell<Vec<DomRoot<MessagePort>>> = RefCell::new(Vec::new())
|
||||
}
|
||||
|
||||
struct PortMessageTask {
|
||||
origin: String,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
pub struct MessagePortInternal {
|
||||
dom_port: RefCell<Option<Trusted<MessagePort>>>,
|
||||
port_message_queue: RefCell<PortMessageQueue>,
|
||||
enabled: Cell<bool>,
|
||||
has_been_shipped: Cell<bool>,
|
||||
entangled_port: RefCell<Option<Arc<ReentrantMutex<MessagePortInternal>>>>,
|
||||
pending_port_messages: RefCell<VecDeque<PortMessageTask>>,
|
||||
}
|
||||
|
||||
impl MessagePortInternal {
|
||||
fn new(port_message_queue: PortMessageQueue) -> MessagePortInternal {
|
||||
MessagePortInternal {
|
||||
dom_port: RefCell::new(None),
|
||||
port_message_queue: RefCell::new(port_message_queue),
|
||||
enabled: Cell::new(false),
|
||||
has_been_shipped: Cell::new(false),
|
||||
entangled_port: RefCell::new(None),
|
||||
pending_port_messages: RefCell::new(VecDeque::new()),
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-postmessage>
|
||||
// Step 7 substeps
|
||||
#[allow(unrooted_must_root)]
|
||||
fn process_pending_port_messages(&self) {
|
||||
let PortMessageTask { origin, data } = match self.pending_port_messages.borrow_mut().pop_front() {
|
||||
Some(task) => task,
|
||||
None => return,
|
||||
};
|
||||
|
||||
// Substep 1
|
||||
let final_target_port = self.dom_port.borrow().as_ref().unwrap().root();
|
||||
|
||||
// Substep 2
|
||||
let target_global = final_target_port.global();
|
||||
|
||||
// Substep 3-4
|
||||
rooted!(in(target_global.get_cx()) let mut message_clone = UndefinedValue());
|
||||
let deserialize_result = StructuredCloneData::Vector(data).read(
|
||||
&target_global,
|
||||
message_clone.handle_mut()
|
||||
);
|
||||
if !deserialize_result {
|
||||
return;
|
||||
}
|
||||
|
||||
// Substep 5
|
||||
let new_ports = TRANSFERRED_MESSAGE_PORTS.with(|list| {
|
||||
mem::replace(&mut *list.borrow_mut(), vec![])
|
||||
});
|
||||
|
||||
// Substep 6
|
||||
MessageEvent::dispatch_jsval(
|
||||
final_target_port.upcast(),
|
||||
&target_global,
|
||||
message_clone.handle(),
|
||||
Some(&origin),
|
||||
None,
|
||||
new_ports,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DenyPublicFields, DomObject, MallocSizeOf)]
|
||||
#[must_root]
|
||||
#[repr(C)]
|
||||
#[dom_struct]
|
||||
/// The MessagePort used in the DOM.
|
||||
pub struct MessagePort {
|
||||
eventtarget: EventTarget,
|
||||
message_port_id: MessagePortId,
|
||||
entangled_port: RefCell<Option<MessagePortId>>,
|
||||
detached: Cell<bool>,
|
||||
#[ignore_malloc_size_of = "Defined in std"]
|
||||
message_port_internal: Arc<ReentrantMutex<MessagePortInternal>>,
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
unsafe impl JSTraceable for MessagePort {
|
||||
unsafe fn trace(&self, trc: *mut JSTracer) {
|
||||
if !self.detached.get() {
|
||||
self.eventtarget.trace(trc);
|
||||
}
|
||||
// Otherwise, do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
impl HasParent for MessagePort {
|
||||
type Parent = EventTarget;
|
||||
|
||||
fn as_parent(&self) -> &EventTarget {
|
||||
&self.eventtarget
|
||||
}
|
||||
}
|
||||
|
||||
impl MessagePort {
|
||||
fn new_inherited(global: &GlobalScope) -> MessagePort {
|
||||
fn new_inherited(message_port_id: MessagePortId) -> MessagePort {
|
||||
MessagePort {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
entangled_port: RefCell::new(None),
|
||||
detached: Cell::new(false),
|
||||
message_port_internal: Arc::new(
|
||||
ReentrantMutex::new(
|
||||
MessagePortInternal::new(global.port_message_queue().clone())
|
||||
)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn new_transferred(message_port_internal: Arc<ReentrantMutex<MessagePortInternal>>) -> MessagePort {
|
||||
MessagePort {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
detached: Cell::new(false),
|
||||
message_port_internal,
|
||||
message_port_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#create-a-new-messageport-object>
|
||||
pub fn new(owner: &GlobalScope) -> DomRoot<MessagePort> {
|
||||
let message_port = reflect_dom_object(Box::new(MessagePort::new_inherited(owner)), owner, Wrap);
|
||||
{
|
||||
let internal = message_port.message_port_internal.lock().unwrap();
|
||||
*internal.dom_port.borrow_mut() = Some(Trusted::new(&*message_port));
|
||||
}
|
||||
message_port
|
||||
let port_id = MessagePortId::new();
|
||||
reflect_dom_object(Box::new(MessagePort::new_inherited(port_id)), owner, Wrap)
|
||||
}
|
||||
|
||||
/// Create a new port for an incoming transfer-received one.
|
||||
fn new_transferred(
|
||||
owner: &GlobalScope,
|
||||
transferred_port: MessagePortId,
|
||||
entangled_port: Option<MessagePortId>,
|
||||
) -> DomRoot<MessagePort> {
|
||||
reflect_dom_object(
|
||||
Box::new(MessagePort {
|
||||
message_port_id: transferred_port,
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
detached: Cell::new(false),
|
||||
entangled_port: RefCell::new(entangled_port),
|
||||
}),
|
||||
owner,
|
||||
Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#entangle>
|
||||
pub fn entangle(&self, other: &MessagePort) {
|
||||
{
|
||||
let internal = self.message_port_internal.lock().unwrap();
|
||||
*internal.entangled_port.borrow_mut() = Some(other.message_port_internal.clone());
|
||||
}
|
||||
let internal = other.message_port_internal.lock().unwrap();
|
||||
*internal.entangled_port.borrow_mut() = Some(self.message_port_internal.clone());
|
||||
pub fn entangle(&self, other_id: MessagePortId) {
|
||||
*self.entangled_port.borrow_mut() = Some(other_id);
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-postmessage>
|
||||
// Step 7 substeps
|
||||
fn process_pending_port_messages(&self) {
|
||||
if self.detached.get() { return; }
|
||||
let internal = self.message_port_internal.lock().unwrap();
|
||||
internal.process_pending_port_messages();
|
||||
pub fn message_port_id(&self) -> &MessagePortId {
|
||||
&self.message_port_id
|
||||
}
|
||||
|
||||
pub fn detached(&self) -> bool {
|
||||
self.detached.get()
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#handler-messageport-onmessage>
|
||||
fn set_onmessage(&self, listener: Option<Rc<EventHandlerNonNull>>) {
|
||||
let eventtarget = self.upcast::<EventTarget>();
|
||||
eventtarget.set_event_handler_common("message", listener);
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#message-port-post-message-steps>
|
||||
fn post_message_impl(
|
||||
&self,
|
||||
cx: SafeJSContext,
|
||||
message: HandleValue,
|
||||
transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
|
||||
) -> ErrorResult {
|
||||
if self.detached.get() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Step 1 is the transfer argument.
|
||||
|
||||
let target_port = self.entangled_port.borrow();
|
||||
|
||||
// Step 3
|
||||
let mut doomed = false;
|
||||
|
||||
let ports = transfer
|
||||
.iter()
|
||||
.filter_map(|&obj| root_from_object::<MessagePort>(obj, *cx).ok());
|
||||
for port in ports {
|
||||
// Step 2
|
||||
if port.message_port_id() == self.message_port_id() {
|
||||
return Err(Error::DataClone);
|
||||
}
|
||||
|
||||
// Step 4
|
||||
if let Some(target_id) = target_port.as_ref() {
|
||||
if port.message_port_id() == target_id {
|
||||
doomed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 5
|
||||
let data = structuredclone::write(cx, message, Some(transfer))?;
|
||||
|
||||
if doomed {
|
||||
// TODO: The spec says to optionally report such a case to a dev console.
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Step 6, done in MessagePortImpl.
|
||||
|
||||
let incumbent = match GlobalScope::incumbent() {
|
||||
None => unreachable!("postMessage called with no incumbent global"),
|
||||
Some(incumbent) => incumbent,
|
||||
};
|
||||
|
||||
// Step 7
|
||||
let task = PortMessageTask {
|
||||
origin: incumbent.origin().immutable().clone(),
|
||||
data,
|
||||
};
|
||||
|
||||
// Have the global proxy this call to the corresponding MessagePortImpl.
|
||||
self.global()
|
||||
.post_messageport_msg(self.message_port_id().clone(), task);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Transferable for MessagePort {
|
||||
/// <https://html.spec.whatwg.org/multipage/#message-ports:transfer-steps>
|
||||
#[allow(unsafe_code)]
|
||||
fn transfer(
|
||||
&self,
|
||||
_closure: *mut raw::c_void,
|
||||
content: *mut *mut raw::c_void,
|
||||
extra_data: *mut u64
|
||||
) -> bool {
|
||||
{
|
||||
let internal = self.message_port_internal.lock().unwrap();
|
||||
// Step 1
|
||||
internal.has_been_shipped.set(true);
|
||||
|
||||
// Step 3
|
||||
if let Some(ref other_port) = *internal.entangled_port.borrow() {
|
||||
let entangled_internal = other_port.lock().unwrap();
|
||||
// Substep 1
|
||||
entangled_internal.has_been_shipped.set(true);
|
||||
}; // This line MUST contain a semicolon, due to the strict drop check rule
|
||||
fn transfer(&self, sc_holder: &mut StructuredDataHolder) -> Result<u64, ()> {
|
||||
if self.detached.get() {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// Steps 2, 3.2 and 4
|
||||
*content = Arc::into_raw(self.message_port_internal.clone()) as *mut raw::c_void;
|
||||
let port_impls = match sc_holder {
|
||||
StructuredDataHolder::Write(port_impls) => port_impls,
|
||||
_ => panic!("Unexpected variant of StructuredDataHolder"),
|
||||
};
|
||||
|
||||
*extra_data = 0;
|
||||
self.detached.set(true);
|
||||
let id = self.message_port_id();
|
||||
|
||||
// 1. Run local transfer logic, and return the object to be transferred.
|
||||
let transferred_port = self.global().mark_port_as_transferred(id);
|
||||
|
||||
// 2. Store the transferred object at a given key.
|
||||
if let Some(ports) = port_impls.as_mut() {
|
||||
ports.insert(id.clone(), transferred_port);
|
||||
} else {
|
||||
let mut ports = HashMap::new();
|
||||
ports.insert(id.clone(), transferred_port);
|
||||
*port_impls = Some(ports);
|
||||
}
|
||||
|
||||
true
|
||||
let PipelineNamespaceId(name_space) = id.clone().namespace_id;
|
||||
let MessagePortIndex(index) = id.clone().index;
|
||||
let index = index.get();
|
||||
|
||||
let mut big: [u8; 8] = [0; 8];
|
||||
let name_space = name_space.to_ne_bytes();
|
||||
let index = index.to_ne_bytes();
|
||||
|
||||
let (left, right) = big.split_at_mut(4);
|
||||
left.copy_from_slice(&name_space);
|
||||
right.copy_from_slice(&index);
|
||||
|
||||
// 3. Return a u64 representation of the key where the object is stored.
|
||||
Ok(u64::from_ne_bytes(big))
|
||||
}
|
||||
|
||||
/// https://html.spec.whatwg.org/multipage/#message-ports:transfer-receiving-steps
|
||||
#[allow(unrooted_must_root, unsafe_code)]
|
||||
fn transfer_receive(
|
||||
cx: *mut JSContext,
|
||||
_r: *mut JSStructuredCloneReader,
|
||||
_closure: *mut raw::c_void,
|
||||
content: *mut raw::c_void,
|
||||
_extra_data: u64,
|
||||
return_object: MutableHandleObject
|
||||
) -> bool {
|
||||
let internal = unsafe { Arc::from_raw(content as *const ReentrantMutex<MessagePortInternal>) };
|
||||
let value = MessagePort::new_transferred(internal);
|
||||
|
||||
// Step 2
|
||||
let owner = unsafe { GlobalScope::from_context(cx) };
|
||||
let message_port = reflect_dom_object(Box::new(value), &*owner, Wrap);
|
||||
|
||||
{
|
||||
let internal = message_port.message_port_internal.lock().unwrap();
|
||||
|
||||
// Step 1
|
||||
internal.has_been_shipped.set(true);
|
||||
|
||||
let dom_port = Trusted::new(&*message_port);
|
||||
internal.enabled.set(false);
|
||||
*internal.dom_port.borrow_mut() = Some(dom_port);
|
||||
*internal.port_message_queue.borrow_mut() = owner.port_message_queue().clone();
|
||||
}
|
||||
return_object.set(message_port.reflector().rootable().get());
|
||||
TRANSFERRED_MESSAGE_PORTS.with(|list| {
|
||||
list.borrow_mut().push(message_port);
|
||||
});
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn detached(&self) -> Option<bool> {
|
||||
Some(self.detached.get())
|
||||
}
|
||||
|
||||
fn set_detached(&self, value: bool) {
|
||||
self.detached.set(value);
|
||||
}
|
||||
|
||||
fn transferable(&self) -> bool {
|
||||
!self.detached.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl MessagePortMethods for MessagePort {
|
||||
#[allow(unsafe_code)]
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-postmessage>
|
||||
unsafe fn PostMessage(
|
||||
&self,
|
||||
cx: *mut JSContext,
|
||||
message: HandleValue,
|
||||
transfer: CustomAutoRooterGuard<Option<Vec<*mut JSObject>>>,
|
||||
) -> ErrorResult {
|
||||
if self.detached.get() { return Ok(()); }
|
||||
let internal = self.message_port_internal.lock().unwrap();
|
||||
// Step 1
|
||||
let target_port = internal.entangled_port.borrow();
|
||||
|
||||
// Step 3
|
||||
let mut doomed = false;
|
||||
|
||||
rooted!(in(cx) let mut val = UndefinedValue());
|
||||
let transfer = match *transfer {
|
||||
Some(ref vec) => {
|
||||
let ports = vec.iter().filter_map(|&obj| root_from_object::<MessagePort>(obj).ok());
|
||||
for port in ports {
|
||||
// Step 2
|
||||
if Arc::ptr_eq(&port.message_port_internal, &self.message_port_internal) {
|
||||
return Err(Error::DataClone);
|
||||
}
|
||||
|
||||
// Step 4
|
||||
if let Some(target) = target_port.as_ref() {
|
||||
if Arc::ptr_eq(&port.message_port_internal, target) {
|
||||
doomed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vec.to_jsval(cx, val.handle_mut());
|
||||
val
|
||||
}
|
||||
None => {
|
||||
Vec::<*mut JSObject>::new().to_jsval(cx, val.handle_mut());
|
||||
val
|
||||
}
|
||||
owner: &DomRoot<GlobalScope>,
|
||||
sc_holder: &mut StructuredDataHolder,
|
||||
extra_data: u64,
|
||||
return_object: MutableHandleObject,
|
||||
) -> Result<(), ()> {
|
||||
let (message_ports, port_impls) = match sc_holder {
|
||||
StructuredDataHolder::Read {
|
||||
message_ports,
|
||||
port_impls,
|
||||
..
|
||||
} => (message_ports, port_impls),
|
||||
_ => panic!("Unexpected variant of StructuredDataHolder"),
|
||||
};
|
||||
|
||||
// Step 5
|
||||
let data = StructuredCloneData::write(cx, message, transfer.handle())?.move_to_arraybuffer();
|
||||
// 1. Re-build the key for the storage location
|
||||
// of the transferred object.
|
||||
let big: [u8; 8] = extra_data.to_ne_bytes();
|
||||
let (name_space, index) = big.split_at(4);
|
||||
|
||||
// Step 6
|
||||
if target_port.is_none() || doomed { return Ok(()); }
|
||||
let namespace_id = PipelineNamespaceId(u32::from_ne_bytes(
|
||||
name_space
|
||||
.try_into()
|
||||
.expect("name_space to be a slice of four."),
|
||||
));
|
||||
let index = MessagePortIndex(
|
||||
NonZeroU32::new(u32::from_ne_bytes(
|
||||
index.try_into().expect("index to be a slice of four."),
|
||||
))
|
||||
.expect("Index to be non-zero"),
|
||||
);
|
||||
|
||||
// Step 7
|
||||
let task = PortMessageTask {
|
||||
origin: self.global().origin().immutable().ascii_serialization(),
|
||||
data,
|
||||
let id = MessagePortId {
|
||||
namespace_id,
|
||||
index,
|
||||
};
|
||||
|
||||
{
|
||||
let target_port = target_port.as_ref().unwrap();
|
||||
let target_internal = target_port.lock().unwrap();
|
||||
target_internal.pending_port_messages.borrow_mut().push_back(task);
|
||||
|
||||
if target_internal.enabled.get() {
|
||||
let target_port = target_port.clone();
|
||||
let _ = target_internal.port_message_queue.borrow().queue(
|
||||
task!(process_pending_port_messages: move || {
|
||||
let internal = target_port.lock().unwrap();
|
||||
internal.process_pending_port_messages();
|
||||
}),
|
||||
&self.global()
|
||||
);
|
||||
// 2. Get the transferred object from its storage, using the key.
|
||||
// Assign the transfer-received port-impl, and total number of transferred ports.
|
||||
let (ports_len, port_impl) = if let Some(ports) = port_impls.as_mut() {
|
||||
let ports_len = ports.len();
|
||||
let port_impl = ports.remove(&id).expect("Transferred port to be stored");
|
||||
if ports.is_empty() {
|
||||
*port_impls = None;
|
||||
}
|
||||
(ports_len, port_impl)
|
||||
} else {
|
||||
panic!("A messageport was transfer-received, yet the SC holder does not have any port impls");
|
||||
};
|
||||
|
||||
let transferred_port =
|
||||
MessagePort::new_transferred(&**owner, id.clone(), port_impl.entangled_port_id());
|
||||
owner.track_message_port(&transferred_port, Some(port_impl));
|
||||
|
||||
return_object.set(transferred_port.reflector().rootable().get());
|
||||
|
||||
// Store the DOM port where it will be passed along to script in the message-event.
|
||||
if let Some(ports) = message_ports.as_mut() {
|
||||
ports.push(transferred_port);
|
||||
} else {
|
||||
let mut ports = Vec::with_capacity(ports_len);
|
||||
ports.push(transferred_port);
|
||||
*message_ports = Some(ports);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl MessagePortMethods for MessagePort {
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-postmessage>
|
||||
fn PostMessage(
|
||||
&self,
|
||||
cx: SafeJSContext,
|
||||
message: HandleValue,
|
||||
transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
|
||||
) -> ErrorResult {
|
||||
if self.detached.get() {
|
||||
return Ok(());
|
||||
}
|
||||
self.post_message_impl(cx, message, transfer)
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-postmessage>
|
||||
fn PostMessage_(
|
||||
&self,
|
||||
cx: SafeJSContext,
|
||||
message: HandleValue,
|
||||
options: RootedTraceableBox<PostMessageOptions>,
|
||||
) -> ErrorResult {
|
||||
if self.detached.get() {
|
||||
return Ok(());
|
||||
}
|
||||
let mut rooted = CustomAutoRooter::new(
|
||||
options
|
||||
.transfer
|
||||
.as_ref()
|
||||
.unwrap_or(&Vec::with_capacity(0))
|
||||
.iter()
|
||||
.map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
|
||||
.collect(),
|
||||
);
|
||||
let guard = CustomAutoRooterGuard::new(*cx, &mut rooted);
|
||||
self.post_message_impl(cx, message, guard)
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-start>
|
||||
fn Start(&self) {
|
||||
let len = {
|
||||
let internal = self.message_port_internal.lock().unwrap();
|
||||
if internal.enabled.get() {
|
||||
return;
|
||||
}
|
||||
internal.enabled.set(true);
|
||||
let messages = internal.pending_port_messages.borrow();
|
||||
messages.len()
|
||||
};
|
||||
|
||||
let global = self.global();
|
||||
for _ in 0..len {
|
||||
let port = Trusted::new(self);
|
||||
let _ = global.port_message_queue().queue(
|
||||
task!(process_pending_port_messages: move || {
|
||||
let this = port.root();
|
||||
this.process_pending_port_messages();
|
||||
}),
|
||||
&global
|
||||
);
|
||||
if self.detached.get() {
|
||||
return;
|
||||
}
|
||||
self.global().start_message_port(self.message_port_id());
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-close>
|
||||
fn Close(&self) {
|
||||
// Step 1
|
||||
self.detached.set(true);
|
||||
|
||||
// Step 2
|
||||
let maybe_port = {
|
||||
let internal = self.message_port_internal.lock().unwrap();
|
||||
let mut maybe_port = internal.entangled_port.borrow_mut();
|
||||
maybe_port.take()
|
||||
};
|
||||
|
||||
if let Some(other) = maybe_port {
|
||||
let other_internal = other.lock().unwrap();
|
||||
*other_internal.entangled_port.borrow_mut() = None;
|
||||
if self.detached.get() {
|
||||
return;
|
||||
}
|
||||
self.detached.set(true);
|
||||
self.global().close_message_port(self.message_port_id());
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#handler-messageport-onmessage>
|
||||
fn GetOnmessage(&self) -> Option<Rc<EventHandlerNonNull>> {
|
||||
if self.detached.get() {
|
||||
return None;
|
||||
}
|
||||
let eventtarget = self.upcast::<EventTarget>();
|
||||
eventtarget.get_event_handler_common("message")
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#handler-messageport-onmessage>
|
||||
fn SetOnmessage(&self, listener: Option<Rc<EventHandlerNonNull>>) {
|
||||
self.Start();
|
||||
let eventtarget = self.upcast::<EventTarget>();
|
||||
eventtarget.set_event_handler_common("message", listener)
|
||||
if self.detached.get() {
|
||||
return;
|
||||
}
|
||||
self.set_onmessage(listener);
|
||||
// Note: we cannot use the event_handler macro, due to the need to start the port.
|
||||
self.global().start_message_port(self.message_port_id());
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#handler-messageport-onmessageerror>
|
||||
event_handler!(messageerror, GetOnmessageerror, SetOnmessageerror);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue