constellation_traits/structured_data/
transferable.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! This module contains implementations in script that are transferable as per
6//! <https://html.spec.whatwg.org/multipage/#transferable-objects>. The implementations are here
7//! instead of in script as they need to be passed through the Constellation.
8
9use std::collections::VecDeque;
10
11use base::id::MessagePortId;
12use malloc_size_of_derive::MallocSizeOf;
13use serde::{Deserialize, Serialize};
14use strum::EnumIter;
15
16use crate::PortMessageTask;
17
18#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
19pub struct TransformStreamData {
20    pub readable: (MessagePortId, MessagePortImpl),
21    pub writable: (MessagePortId, MessagePortImpl),
22}
23
24/// All the DOM interfaces that can be transferred.
25#[derive(Clone, Copy, Debug, EnumIter)]
26pub enum Transferrable {
27    /// The `ImageBitmap` interface.
28    ImageBitmap,
29    /// The `MessagePort` interface.
30    MessagePort,
31    /// The `OffscreenCanvas` interface.
32    OffscreenCanvas,
33    /// The `ReadableStream` interface.
34    ReadableStream,
35    /// The `WritableStream` interface.
36    WritableStream,
37    /// The `TransformStream` interface.
38    TransformStream,
39}
40
41#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
42enum MessagePortState {
43    /// <https://html.spec.whatwg.org/multipage/#detached>
44    Detached,
45    /// <https://html.spec.whatwg.org/multipage/#port-message-queue>
46    /// The message-queue of this port is enabled,
47    /// the boolean represents awaiting completion of a transfer.
48    Enabled(bool),
49    /// <https://html.spec.whatwg.org/multipage/#port-message-queue>
50    /// The message-queue of this port is disabled,
51    /// the boolean represents awaiting completion of a transfer.
52    Disabled(bool),
53}
54
55#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
56/// The data and logic backing the DOM managed MessagePort.
57pub struct MessagePortImpl {
58    /// The current state of the port.
59    state: MessagePortState,
60
61    /// <https://html.spec.whatwg.org/multipage/#entangle>
62    entangled_port: Option<MessagePortId>,
63
64    /// <https://html.spec.whatwg.org/multipage/#port-message-queue>
65    message_buffer: Option<VecDeque<PortMessageTask>>,
66
67    /// The UUID of this port.
68    message_port_id: MessagePortId,
69}
70
71impl MessagePortImpl {
72    /// Create a new messageport impl.
73    pub fn new(port_id: MessagePortId) -> MessagePortImpl {
74        MessagePortImpl {
75            state: MessagePortState::Disabled(false),
76            entangled_port: None,
77            message_buffer: None,
78            message_port_id: port_id,
79        }
80    }
81
82    /// Get the Id.
83    pub fn message_port_id(&self) -> &MessagePortId {
84        &self.message_port_id
85    }
86
87    /// Maybe get the Id of the entangled port.
88    pub fn entangled_port_id(&self) -> Option<MessagePortId> {
89        self.entangled_port
90    }
91
92    /// <https://html.spec.whatwg.org/multipage/#disentangle>
93    pub fn disentangle(&mut self) -> Option<MessagePortId> {
94        self.entangled_port.take()
95    }
96
97    /// <https://html.spec.whatwg.org/multipage/#entangle>
98    pub fn entangle(&mut self, other_id: MessagePortId) {
99        self.entangled_port = Some(other_id);
100    }
101
102    /// Is this port enabled?
103    pub fn enabled(&self) -> bool {
104        matches!(self.state, MessagePortState::Enabled(_))
105    }
106
107    /// Mark this port as having been shipped.
108    /// <https://html.spec.whatwg.org/multipage/#has-been-shipped>
109    pub fn set_has_been_shipped(&mut self) {
110        match self.state {
111            MessagePortState::Detached => {
112                panic!("Messageport set_has_been_shipped called in detached state")
113            },
114            MessagePortState::Enabled(_) => self.state = MessagePortState::Enabled(true),
115            MessagePortState::Disabled(_) => self.state = MessagePortState::Disabled(true),
116        }
117    }
118
119    /// Handle the completion of the transfer,
120    /// this is data received from the constellation.
121    pub fn complete_transfer(&mut self, mut tasks: VecDeque<PortMessageTask>) {
122        match self.state {
123            MessagePortState::Detached => return,
124            MessagePortState::Enabled(_) => self.state = MessagePortState::Enabled(false),
125            MessagePortState::Disabled(_) => self.state = MessagePortState::Disabled(false),
126        }
127
128        // Note: these are the tasks that were buffered while the transfer was ongoing,
129        // hence they need to execute first.
130        // The global will call `start` if we are enabled,
131        // which will add tasks on the event-loop to dispatch incoming messages.
132        match self.message_buffer {
133            Some(ref mut incoming_buffer) => {
134                while let Some(task) = tasks.pop_back() {
135                    incoming_buffer.push_front(task);
136                }
137            },
138            None => self.message_buffer = Some(tasks),
139        }
140    }
141
142    /// A message was received from our entangled port,
143    /// returns an optional task to be dispatched.
144    pub fn handle_incoming(&mut self, task: PortMessageTask) -> Option<PortMessageTask> {
145        let should_dispatch = match self.state {
146            MessagePortState::Detached => return None,
147            MessagePortState::Enabled(in_transfer) => !in_transfer,
148            MessagePortState::Disabled(_) => false,
149        };
150
151        if should_dispatch {
152            Some(task)
153        } else {
154            match self.message_buffer {
155                Some(ref mut buffer) => {
156                    buffer.push_back(task);
157                },
158                None => {
159                    let mut queue = VecDeque::new();
160                    queue.push_back(task);
161                    self.message_buffer = Some(queue);
162                },
163            }
164            None
165        }
166    }
167
168    /// <https://html.spec.whatwg.org/multipage/#dom-messageport-start>
169    /// returns an optional queue of tasks that were buffered while the port was disabled.
170    pub fn start(&mut self) -> Option<VecDeque<PortMessageTask>> {
171        match self.state {
172            MessagePortState::Detached => return None,
173            MessagePortState::Enabled(_) => {},
174            MessagePortState::Disabled(in_transfer) => {
175                self.state = MessagePortState::Enabled(in_transfer);
176            },
177        }
178        if let MessagePortState::Enabled(true) = self.state {
179            return None;
180        }
181        self.message_buffer.take()
182    }
183
184    /// <https://html.spec.whatwg.org/multipage/#dom-messageport-close>
185    pub fn close(&mut self) {
186        // Step 1
187        self.state = MessagePortState::Detached;
188    }
189}
190
191#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
192/// A struct supporting the transfer of OffscreenCanvas, which loosely
193/// corresponds to the dataHolder in
194/// <https://html.spec.whatwg.org/multipage/#the-offscreencanvas-interface:offscreencanvas-16>
195pub struct TransferableOffscreenCanvas {
196    pub width: u64,
197    pub height: u64,
198}