aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/canvas_context.rs182
-rw-r--r--components/script/canvas_state.rs13
-rw-r--r--components/script/dom/element.rs16
-rw-r--r--components/script/dom/globalscope.rs199
-rw-r--r--components/script/dom/htmlcanvaselement.rs99
-rw-r--r--components/script/dom/htmldetailselement.rs4
-rw-r--r--components/script/dom/macros.rs23
-rw-r--r--components/script/dom/messageport.rs38
-rw-r--r--components/script/dom/node.rs62
-rw-r--r--components/script/dom/nodelist.rs1
-rw-r--r--components/script/dom/offscreencanvas.rs58
-rw-r--r--components/script/dom/offscreencanvasrenderingcontext2d.rs29
-rw-r--r--components/script/dom/readablestream.rs8
-rw-r--r--components/script/dom/underlyingsourcecontainer.rs2
-rw-r--r--components/script/dom/writablestream.rs4
-rw-r--r--components/script/dom/writablestreamdefaultcontroller.rs10
16 files changed, 512 insertions, 236 deletions
diff --git a/components/script/canvas_context.rs b/components/script/canvas_context.rs
index d49d31997e1..d85877c0f41 100644
--- a/components/script/canvas_context.rs
+++ b/components/script/canvas_context.rs
@@ -5,6 +5,7 @@
//! Common interfaces for Canvas Contexts
use euclid::default::Size2D;
+use script_bindings::root::Dom;
use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource};
use snapshot::Snapshot;
@@ -12,6 +13,10 @@ use crate::dom::bindings::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanva
use crate::dom::bindings::inheritance::Castable;
use crate::dom::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::node::{Node, NodeDamage};
+use crate::dom::types::{
+ CanvasRenderingContext2D, GPUCanvasContext, OffscreenCanvas, OffscreenCanvasRenderingContext2D,
+ WebGL2RenderingContext, WebGLRenderingContext,
+};
pub(crate) trait LayoutCanvasRenderingContextHelpers {
fn canvas_data_source(self) -> HTMLCanvasDataSource;
@@ -85,3 +90,180 @@ impl CanvasHelpers for HTMLCanvasElementOrOffscreenCanvas {
}
}
}
+
+/// Non rooted variant of [`crate::dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::RenderingContext`]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+#[derive(Clone, JSTraceable, MallocSizeOf)]
+pub(crate) enum RenderingContext {
+ Placeholder(Dom<OffscreenCanvas>),
+ Context2d(Dom<CanvasRenderingContext2D>),
+ WebGL(Dom<WebGLRenderingContext>),
+ WebGL2(Dom<WebGL2RenderingContext>),
+ #[cfg(feature = "webgpu")]
+ WebGPU(Dom<GPUCanvasContext>),
+}
+
+impl CanvasContext for RenderingContext {
+ type ID = ();
+
+ fn context_id(&self) -> Self::ID {}
+
+ fn canvas(&self) -> HTMLCanvasElementOrOffscreenCanvas {
+ match self {
+ RenderingContext::Placeholder(context) => (*context.context().unwrap()).canvas(),
+ RenderingContext::Context2d(context) => context.canvas(),
+ RenderingContext::WebGL(context) => context.canvas(),
+ RenderingContext::WebGL2(context) => context.canvas(),
+ #[cfg(feature = "webgpu")]
+ RenderingContext::WebGPU(context) => context.canvas(),
+ }
+ }
+
+ fn resize(&self) {
+ match self {
+ RenderingContext::Placeholder(context) => (*context.context().unwrap()).resize(),
+ RenderingContext::Context2d(context) => context.resize(),
+ RenderingContext::WebGL(context) => context.resize(),
+ RenderingContext::WebGL2(context) => context.resize(),
+ #[cfg(feature = "webgpu")]
+ RenderingContext::WebGPU(context) => context.resize(),
+ }
+ }
+
+ fn get_image_data(&self) -> Option<Snapshot> {
+ match self {
+ RenderingContext::Placeholder(context) => {
+ (*context.context().unwrap()).get_image_data()
+ },
+ RenderingContext::Context2d(context) => context.get_image_data(),
+ RenderingContext::WebGL(context) => context.get_image_data(),
+ RenderingContext::WebGL2(context) => context.get_image_data(),
+ #[cfg(feature = "webgpu")]
+ RenderingContext::WebGPU(context) => context.get_image_data(),
+ }
+ }
+
+ fn origin_is_clean(&self) -> bool {
+ match self {
+ RenderingContext::Placeholder(context) => {
+ (*context.context().unwrap()).origin_is_clean()
+ },
+ RenderingContext::Context2d(context) => context.origin_is_clean(),
+ RenderingContext::WebGL(context) => context.origin_is_clean(),
+ RenderingContext::WebGL2(context) => context.origin_is_clean(),
+ #[cfg(feature = "webgpu")]
+ RenderingContext::WebGPU(context) => context.origin_is_clean(),
+ }
+ }
+
+ fn size(&self) -> Size2D<u64> {
+ match self {
+ RenderingContext::Placeholder(context) => (*context.context().unwrap()).size(),
+ RenderingContext::Context2d(context) => context.size(),
+ RenderingContext::WebGL(context) => context.size(),
+ RenderingContext::WebGL2(context) => context.size(),
+ #[cfg(feature = "webgpu")]
+ RenderingContext::WebGPU(context) => context.size(),
+ }
+ }
+
+ fn mark_as_dirty(&self) {
+ match self {
+ RenderingContext::Placeholder(context) => (*context.context().unwrap()).mark_as_dirty(),
+ RenderingContext::Context2d(context) => context.mark_as_dirty(),
+ RenderingContext::WebGL(context) => context.mark_as_dirty(),
+ RenderingContext::WebGL2(context) => context.mark_as_dirty(),
+ #[cfg(feature = "webgpu")]
+ RenderingContext::WebGPU(context) => context.mark_as_dirty(),
+ }
+ }
+
+ fn update_rendering(&self) {
+ match self {
+ RenderingContext::Placeholder(context) => {
+ (*context.context().unwrap()).update_rendering()
+ },
+ RenderingContext::Context2d(context) => context.update_rendering(),
+ RenderingContext::WebGL(context) => context.update_rendering(),
+ RenderingContext::WebGL2(context) => context.update_rendering(),
+ #[cfg(feature = "webgpu")]
+ RenderingContext::WebGPU(context) => context.update_rendering(),
+ }
+ }
+
+ fn onscreen(&self) -> bool {
+ match self {
+ RenderingContext::Placeholder(context) => (*context.context().unwrap()).onscreen(),
+ RenderingContext::Context2d(context) => context.onscreen(),
+ RenderingContext::WebGL(context) => context.onscreen(),
+ RenderingContext::WebGL2(context) => context.onscreen(),
+ #[cfg(feature = "webgpu")]
+ RenderingContext::WebGPU(context) => context.onscreen(),
+ }
+ }
+}
+
+/// Non rooted variant of [`crate::dom::bindings::codegen::Bindings::OffscreenCanvasBinding::OffscreenRenderingContext`]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+#[derive(Clone, JSTraceable, MallocSizeOf)]
+pub(crate) enum OffscreenRenderingContext {
+ Context2d(Dom<OffscreenCanvasRenderingContext2D>),
+ //WebGL(Dom<WebGLRenderingContext>),
+ //WebGL2(Dom<WebGL2RenderingContext>),
+ //#[cfg(feature = "webgpu")]
+ //WebGPU(Dom<GPUCanvasContext>),
+}
+
+impl CanvasContext for OffscreenRenderingContext {
+ type ID = ();
+
+ fn context_id(&self) -> Self::ID {}
+
+ fn canvas(&self) -> HTMLCanvasElementOrOffscreenCanvas {
+ match self {
+ OffscreenRenderingContext::Context2d(context) => context.canvas(),
+ }
+ }
+
+ fn resize(&self) {
+ match self {
+ OffscreenRenderingContext::Context2d(context) => context.resize(),
+ }
+ }
+
+ fn get_image_data(&self) -> Option<Snapshot> {
+ match self {
+ OffscreenRenderingContext::Context2d(context) => context.get_image_data(),
+ }
+ }
+
+ fn origin_is_clean(&self) -> bool {
+ match self {
+ OffscreenRenderingContext::Context2d(context) => context.origin_is_clean(),
+ }
+ }
+
+ fn size(&self) -> Size2D<u64> {
+ match self {
+ OffscreenRenderingContext::Context2d(context) => context.size(),
+ }
+ }
+
+ fn mark_as_dirty(&self) {
+ match self {
+ OffscreenRenderingContext::Context2d(context) => context.mark_as_dirty(),
+ }
+ }
+
+ fn update_rendering(&self) {
+ match self {
+ OffscreenRenderingContext::Context2d(context) => context.update_rendering(),
+ }
+ }
+
+ fn onscreen(&self) -> bool {
+ match self {
+ OffscreenRenderingContext::Context2d(context) => context.onscreen(),
+ }
+ }
+}
diff --git a/components/script/canvas_state.rs b/components/script/canvas_state.rs
index e9892818e92..dabe6a5728b 100644
--- a/components/script/canvas_state.rs
+++ b/components/script/canvas_state.rs
@@ -36,6 +36,7 @@ use style_traits::{CssWriter, ParsingMode};
use url::Url;
use webrender_api::ImageKey;
+use crate::canvas_context::{OffscreenRenderingContext, RenderingContext};
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::{
CanvasDirection, CanvasFillRule, CanvasImageSource, CanvasLineCap, CanvasLineJoin,
@@ -52,10 +53,10 @@ use crate::dom::canvaspattern::CanvasPattern;
use crate::dom::dommatrix::DOMMatrix;
use crate::dom::element::{Element, cors_setting_for_element};
use crate::dom::globalscope::GlobalScope;
-use crate::dom::htmlcanvaselement::{CanvasContext, HTMLCanvasElement};
+use crate::dom::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::imagedata::ImageData;
use crate::dom::node::{Node, NodeTraits};
-use crate::dom::offscreencanvas::{OffscreenCanvas, OffscreenCanvasContext};
+use crate::dom::offscreencanvas::OffscreenCanvas;
use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
use crate::dom::textmetrics::TextMetrics;
use crate::script_runtime::CanGc;
@@ -522,7 +523,7 @@ impl CanvasState {
if let Some(context) = canvas.context() {
match *context {
- OffscreenCanvasContext::OffscreenContext2d(ref context) => {
+ OffscreenRenderingContext::Context2d(ref context) => {
context.send_canvas_2d_msg(Canvas2dMsg::DrawImageInOther(
self.get_canvas_id(),
image_size,
@@ -577,7 +578,7 @@ impl CanvasState {
if let Some(context) = canvas.context() {
match *context {
- CanvasContext::Context2d(ref context) => {
+ RenderingContext::Context2d(ref context) => {
context.send_canvas_2d_msg(Canvas2dMsg::DrawImageInOther(
self.get_canvas_id(),
image_size,
@@ -586,12 +587,12 @@ impl CanvasState {
smoothing_enabled,
));
},
- CanvasContext::Placeholder(ref context) => {
+ RenderingContext::Placeholder(ref context) => {
let Some(context) = context.context() else {
return Err(Error::InvalidState);
};
match *context {
- OffscreenCanvasContext::OffscreenContext2d(ref context) => context
+ OffscreenRenderingContext::Context2d(ref context) => context
.send_canvas_2d_msg(Canvas2dMsg::DrawImageInOther(
self.get_canvas_id(),
image_size,
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 3a8ac8f0cd8..2831fc3d8f0 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -327,7 +327,21 @@ impl Element {
)
}
- impl_rare_data!(ElementRareData);
+ fn rare_data(&self) -> Ref<Option<Box<ElementRareData>>> {
+ self.rare_data.borrow()
+ }
+
+ fn rare_data_mut(&self) -> RefMut<Option<Box<ElementRareData>>> {
+ self.rare_data.borrow_mut()
+ }
+
+ fn ensure_rare_data(&self) -> RefMut<Box<ElementRareData>> {
+ let mut rare_data = self.rare_data.borrow_mut();
+ if rare_data.is_none() {
+ *rare_data = Some(Default::default());
+ }
+ RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
+ }
pub(crate) fn restyle(&self, damage: NodeDamage) {
let doc = self.node.owner_doc();
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index b3345b90fc0..efa9a9a97ab 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -457,8 +457,9 @@ pub(crate) struct ManagedMessagePort {
/// and only add them, and ask the constellation to complete the transfer,
/// in a subsequent task if the port hasn't been re-transfered.
pending: bool,
- /// Has the port been closed? If closed, it can be dropped and later GC'ed.
- closed: bool,
+ /// Whether the port has been closed by script in this global,
+ /// so it can be removed.
+ explicitly_closed: bool,
/// Note: it may seem strange to use a pair of options, versus for example an enum.
/// But it looks like tranform streams will require both of those in their transfer.
/// This will be resolved when we reach that point of the implementation.
@@ -546,12 +547,17 @@ impl MessageListener {
let mut succeeded = vec![];
let mut failed = HashMap::new();
- for (id, buffer) in ports.into_iter() {
+ for (id, info) in ports.into_iter() {
if global.is_managing_port(&id) {
succeeded.push(id);
- global.complete_port_transfer(id, buffer);
+ global.complete_port_transfer(
+ id,
+ info.port_message_queue,
+ info.disentangled,
+ CanGc::note()
+ );
} else {
- failed.insert(id, buffer);
+ failed.insert(id, info);
}
}
let _ = global.script_to_constellation_chan().send(
@@ -560,13 +566,21 @@ impl MessageListener {
})
);
},
- MessagePortMsg::CompletePendingTransfer(port_id, buffer) => {
+ MessagePortMsg::CompletePendingTransfer(port_id, info) => {
let context = self.context.clone();
self.task_source.queue(task!(complete_pending: move || {
let global = context.root();
- global.complete_port_transfer(port_id, buffer);
+ global.complete_port_transfer(port_id, info.port_message_queue, info.disentangled, CanGc::note());
}));
},
+ MessagePortMsg::CompleteDisentanglement(port_id) => {
+ let context = self.context.clone();
+ self.task_source
+ .queue(task!(try_complete_disentanglement: move || {
+ let global = context.root();
+ global.try_complete_disentanglement(port_id, CanGc::note());
+ }));
+ },
MessagePortMsg::NewTask(port_id, task) => {
let context = self.context.clone();
self.task_source.queue(task!(process_new_task: move || {
@@ -574,14 +588,6 @@ impl MessageListener {
global.route_task_to_port(port_id, task, CanGc::note());
}));
},
- MessagePortMsg::RemoveMessagePort(port_id) => {
- let context = self.context.clone();
- self.task_source
- .queue(task!(process_remove_message_port: move || {
- let global = context.root();
- global.note_entangled_port_removed(&port_id);
- }));
- },
}
}
}
@@ -871,7 +877,13 @@ impl GlobalScope {
}
/// Complete the transfer of a message-port.
- fn complete_port_transfer(&self, port_id: MessagePortId, tasks: VecDeque<PortMessageTask>) {
+ fn complete_port_transfer(
+ &self,
+ port_id: MessagePortId,
+ tasks: VecDeque<PortMessageTask>,
+ disentangled: bool,
+ can_gc: CanGc,
+ ) {
let should_start = if let MessagePortState::Managed(_id, message_ports) =
&mut *self.message_port_state.borrow_mut()
{
@@ -885,6 +897,10 @@ impl GlobalScope {
}
if let Some(port_impl) = managed_port.port_impl.as_mut() {
port_impl.complete_transfer(tasks);
+ if disentangled {
+ port_impl.disentangle();
+ managed_port.dom_port.disentangle();
+ }
port_impl.enabled()
} else {
panic!("managed-port has no port-impl.");
@@ -895,7 +911,45 @@ impl GlobalScope {
panic!("complete_port_transfer called for an unknown port.");
};
if should_start {
- self.start_message_port(&port_id);
+ self.start_message_port(&port_id, can_gc);
+ }
+ }
+
+ /// The closing of `otherPort`, if it is in a different global.
+ /// <https://html.spec.whatwg.org/multipage/#disentangle>
+ fn try_complete_disentanglement(&self, port_id: MessagePortId, can_gc: CanGc) {
+ let dom_port = if let MessagePortState::Managed(_id, message_ports) =
+ &mut *self.message_port_state.borrow_mut()
+ {
+ let dom_port = if let Some(managed_port) = message_ports.get_mut(&port_id) {
+ if managed_port.pending {
+ unreachable!("CompleteDisentanglement msg received for a pending port.");
+ }
+ let port_impl = managed_port
+ .port_impl
+ .as_mut()
+ .expect("managed-port has no port-impl.");
+ port_impl.disentangle();
+ managed_port.dom_port.as_rooted()
+ } else {
+ // Note: this, and the other return below,
+ // can happen if the port has already been transferred out of this global,
+ // in which case the disentanglement will complete along with the transfer.
+ return;
+ };
+ dom_port
+ } else {
+ return;
+ };
+
+ // Fire an event named close at otherPort.
+ dom_port.upcast().fire_event(atom!("close"), can_gc);
+
+ let res = self.script_to_constellation_chan().send(
+ ScriptToConstellationMessage::DisentanglePorts(port_id, None),
+ );
+ if res.is_err() {
+ warn!("Sending DisentanglePorts failed");
}
}
@@ -951,8 +1005,64 @@ impl GlobalScope {
}
/// <https://html.spec.whatwg.org/multipage/#disentangle>
- pub(crate) fn disentangle_port(&self, _port: &MessagePort) {
- // TODO: #36465
+ pub(crate) fn disentangle_port(&self, port: &MessagePort, can_gc: CanGc) {
+ let initiator_port = port.message_port_id();
+ // Let otherPort be the MessagePort which initiatorPort was entangled with.
+ let Some(other_port) = port.disentangle() else {
+ // Assert: otherPort exists.
+ // Note: ignoring the assert,
+ // because the streams spec seems to disentangle ports that are disentangled already.
+ return;
+ };
+
+ // Disentangle initiatorPort and otherPort, so that they are no longer entangled or associated with each other.
+ // Note: this is done in part here, and in part at the constellation(if otherPort is in another global).
+ let dom_port = if let MessagePortState::Managed(_id, message_ports) =
+ &mut *self.message_port_state.borrow_mut()
+ {
+ let mut dom_port = None;
+ for port_id in &[initiator_port, &other_port] {
+ match message_ports.get_mut(port_id) {
+ None => {
+ continue;
+ },
+ Some(managed_port) => {
+ let port_impl = managed_port
+ .port_impl
+ .as_mut()
+ .expect("managed-port has no port-impl.");
+ managed_port.dom_port.disentangle();
+ port_impl.disentangle();
+
+ if **port_id == other_port {
+ dom_port = Some(managed_port.dom_port.as_rooted())
+ }
+ },
+ }
+ }
+ dom_port
+ } else {
+ panic!("disentangle_port called on a global not managing any ports.");
+ };
+
+ // Fire an event named close at `otherPort`.
+ // Note: done here if the port is managed by the same global as `initialPort`.
+ if let Some(dom_port) = dom_port {
+ dom_port.upcast().fire_event(atom!("close"), can_gc);
+ }
+
+ let chan = self.script_to_constellation_chan().clone();
+ let initiator_port = *initiator_port;
+ self.task_manager()
+ .port_message_queue()
+ .queue(task!(post_message: move || {
+ // Note: we do this in a task to ensure it doesn't affect messages that are still to be routed,
+ // see the task queueing in `post_messageport_msg`.
+ let res = chan.send(ScriptToConstellationMessage::DisentanglePorts(initiator_port, Some(other_port)));
+ if res.is_err() {
+ warn!("Sending DisentanglePorts failed");
+ }
+ }));
}
/// <https://html.spec.whatwg.org/multipage/#entangle>
@@ -984,18 +1094,6 @@ impl GlobalScope {
.send(ScriptToConstellationMessage::EntanglePorts(port1, port2));
}
- /// Note that the entangled port of `port_id` has been removed in another global.
- pub(crate) fn note_entangled_port_removed(&self, port_id: &MessagePortId) {
- // Note: currently this is a no-op,
- // as we only use the `close` method to manage the local lifecyle of a port.
- // This could be used as part of lifecyle management to determine a port can be GC'ed.
- // See https://github.com/servo/servo/issues/25772
- warn!(
- "Entangled port of {:?} has been removed in another global",
- port_id
- );
- }
-
/// Handle the transfer of a port in the current task.
pub(crate) fn mark_port_as_transferred(&self, port_id: &MessagePortId) -> MessagePortImpl {
if let MessagePortState::Managed(_id, message_ports) =
@@ -1021,20 +1119,21 @@ impl GlobalScope {
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-start>
- pub(crate) fn start_message_port(&self, port_id: &MessagePortId) {
- let message_buffer = if let MessagePortState::Managed(_id, message_ports) =
+ pub(crate) fn start_message_port(&self, port_id: &MessagePortId, can_gc: CanGc) {
+ let (message_buffer, dom_port) = if let MessagePortState::Managed(_id, message_ports) =
&mut *self.message_port_state.borrow_mut()
{
- match message_ports.get_mut(port_id) {
+ let (message_buffer, dom_port) = match message_ports.get_mut(port_id) {
None => panic!("start_message_port called on a unknown port."),
Some(managed_port) => {
if let Some(port_impl) = managed_port.port_impl.as_mut() {
- port_impl.start()
+ (port_impl.start(), managed_port.dom_port.as_rooted())
} else {
panic!("managed-port has no port-impl.");
}
},
- }
+ };
+ (message_buffer, dom_port)
} else {
return warn!("start_message_port called on a global not managing any ports.");
};
@@ -1042,6 +1141,18 @@ impl GlobalScope {
for task in message_buffer {
self.route_task_to_port(*port_id, task, CanGc::note());
}
+ if dom_port.disentangled() {
+ // <https://html.spec.whatwg.org/multipage/#disentangle>
+ // Fire an event named close at otherPort.
+ dom_port.upcast().fire_event(atom!("close"), can_gc);
+
+ let res = self.script_to_constellation_chan().send(
+ ScriptToConstellationMessage::DisentanglePorts(*port_id, None),
+ );
+ if res.is_err() {
+ warn!("Sending DisentanglePorts failed");
+ }
+ }
}
}
@@ -1055,7 +1166,7 @@ impl GlobalScope {
Some(managed_port) => {
if let Some(port_impl) = managed_port.port_impl.as_mut() {
port_impl.close();
- managed_port.closed = true;
+ managed_port.explicitly_closed = true;
} else {
panic!("managed-port has no port-impl.");
}
@@ -1436,12 +1547,7 @@ impl GlobalScope {
let to_be_removed: Vec<MessagePortId> = message_ports
.iter()
.filter_map(|(id, managed_port)| {
- if managed_port.closed {
- // Let the constellation know to drop this port and the one it is entangled with,
- // and to forward this message to the script-process where the entangled is found.
- let _ = self
- .script_to_constellation_chan()
- .send(ScriptToConstellationMessage::RemoveMessagePort(*id));
+ if managed_port.explicitly_closed {
Some(*id)
} else {
None
@@ -1451,6 +1557,9 @@ impl GlobalScope {
for id in to_be_removed {
message_ports.remove(&id);
}
+ // Note: ports are only removed throught explicit closure by script in this global.
+ // TODO: #25772
+ // TODO: remove ports when we can be sure their port message queue is empty(via the constellation).
message_ports.is_empty()
} else {
false
@@ -1581,7 +1690,7 @@ impl GlobalScope {
port_impl: Some(port_impl),
dom_port: Dom::from_ref(dom_port),
pending: true,
- closed: false,
+ explicitly_closed: false,
cross_realm_transform_readable: None,
cross_realm_transform_writable: None,
},
@@ -1605,7 +1714,7 @@ impl GlobalScope {
port_impl: Some(port_impl),
dom_port: Dom::from_ref(dom_port),
pending: false,
- closed: false,
+ explicitly_closed: false,
cross_realm_transform_readable: None,
cross_realm_transform_writable: None,
},
diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs
index bb27d28cea8..cc6df183f42 100644
--- a/components/script/dom/htmlcanvaselement.rs
+++ b/components/script/dom/htmlcanvaselement.rs
@@ -27,14 +27,13 @@ use servo_media::streams::registry::MediaStreamId;
use snapshot::Snapshot;
use style::attr::AttrValue;
-use crate::canvas_context::CanvasContext as _;
pub(crate) use crate::canvas_context::*;
use crate::conversions::Convert;
use crate::dom::attr::Attr;
use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::cell::{DomRefCell, Ref, ref_filter_map};
use crate::dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::{
- BlobCallback, HTMLCanvasElementMethods, RenderingContext,
+ BlobCallback, HTMLCanvasElementMethods, RenderingContext as RootedRenderingContext,
};
use crate::dom::bindings::codegen::Bindings::MediaStreamBinding::MediaStreamMethods;
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLContextAttributes;
@@ -104,21 +103,10 @@ impl EncodedImageType {
}
}
-#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
-#[derive(Clone, JSTraceable, MallocSizeOf)]
-pub(crate) enum CanvasContext {
- Placeholder(Dom<OffscreenCanvas>),
- Context2d(Dom<CanvasRenderingContext2D>),
- WebGL(Dom<WebGLRenderingContext>),
- WebGL2(Dom<WebGL2RenderingContext>),
- #[cfg(feature = "webgpu")]
- WebGPU(Dom<GPUCanvasContext>),
-}
-
#[dom_struct]
pub(crate) struct HTMLCanvasElement {
htmlelement: HTMLElement,
- context: DomRefCell<Option<CanvasContext>>,
+ context: DomRefCell<Option<RenderingContext>>,
// This id and hashmap are used to keep track of ongoing toBlob() calls.
callback_id: Cell<u32>,
#[ignore_malloc_size_of = "not implemented for webidl callbacks"]
@@ -159,14 +147,7 @@ impl HTMLCanvasElement {
fn recreate_contexts_after_resize(&self) {
if let Some(ref context) = *self.context.borrow() {
- match *context {
- CanvasContext::Context2d(ref context) => context.resize(),
- CanvasContext::WebGL(ref context) => context.resize(),
- CanvasContext::WebGL2(ref context) => context.resize(),
- #[cfg(feature = "webgpu")]
- CanvasContext::WebGPU(ref context) => context.resize(),
- CanvasContext::Placeholder(ref context) => context.resize(self.get_size().cast()),
- }
+ context.resize()
}
}
@@ -176,23 +157,14 @@ impl HTMLCanvasElement {
pub(crate) fn origin_is_clean(&self) -> bool {
match *self.context.borrow() {
- Some(CanvasContext::Context2d(ref context)) => context.origin_is_clean(),
+ Some(ref context) => context.origin_is_clean(),
_ => true,
}
}
pub(crate) fn mark_as_dirty(&self) {
if let Some(ref context) = *self.context.borrow() {
- match *context {
- CanvasContext::Context2d(ref context) => context.mark_as_dirty(),
- CanvasContext::WebGL(ref context) => context.mark_as_dirty(),
- CanvasContext::WebGL2(ref context) => context.mark_as_dirty(),
- #[cfg(feature = "webgpu")]
- CanvasContext::WebGPU(ref context) => context.mark_as_dirty(),
- CanvasContext::Placeholder(ref _context) => {
- // TODO: Should this be marked as dirty?
- },
- }
+ context.mark_as_dirty()
}
}
@@ -222,12 +194,14 @@ impl LayoutHTMLCanvasElementHelpers for LayoutDom<'_, HTMLCanvasElement> {
fn data(self) -> HTMLCanvasData {
let source = unsafe {
match self.unsafe_get().context.borrow_for_layout().as_ref() {
- Some(CanvasContext::Context2d(context)) => context.to_layout().canvas_data_source(),
- Some(CanvasContext::WebGL(context)) => context.to_layout().canvas_data_source(),
- Some(CanvasContext::WebGL2(context)) => context.to_layout().canvas_data_source(),
+ Some(RenderingContext::Context2d(context)) => {
+ context.to_layout().canvas_data_source()
+ },
+ Some(RenderingContext::WebGL(context)) => context.to_layout().canvas_data_source(),
+ Some(RenderingContext::WebGL2(context)) => context.to_layout().canvas_data_source(),
#[cfg(feature = "webgpu")]
- Some(CanvasContext::WebGPU(context)) => context.to_layout().canvas_data_source(),
- Some(CanvasContext::Placeholder(_)) | None => HTMLCanvasDataSource::Empty,
+ Some(RenderingContext::WebGPU(context)) => context.to_layout().canvas_data_source(),
+ Some(RenderingContext::Placeholder(_)) | None => HTMLCanvasDataSource::Empty,
}
};
@@ -246,14 +220,14 @@ impl LayoutHTMLCanvasElementHelpers for LayoutDom<'_, HTMLCanvasElement> {
}
impl HTMLCanvasElement {
- pub(crate) fn context(&self) -> Option<Ref<CanvasContext>> {
+ pub(crate) fn context(&self) -> Option<Ref<RenderingContext>> {
ref_filter_map(self.context.borrow(), |ctx| ctx.as_ref())
}
fn get_or_init_2d_context(&self, can_gc: CanGc) -> Option<DomRoot<CanvasRenderingContext2D>> {
if let Some(ctx) = self.context() {
return match *ctx {
- CanvasContext::Context2d(ref ctx) => Some(DomRoot::from_ref(ctx)),
+ RenderingContext::Context2d(ref ctx) => Some(DomRoot::from_ref(ctx)),
_ => None,
};
}
@@ -261,7 +235,7 @@ impl HTMLCanvasElement {
let window = self.owner_window();
let size = self.get_size();
let context = CanvasRenderingContext2D::new(window.as_global_scope(), self, size, can_gc);
- *self.context.borrow_mut() = Some(CanvasContext::Context2d(Dom::from_ref(&*context)));
+ *self.context.borrow_mut() = Some(RenderingContext::Context2d(Dom::from_ref(&*context)));
Some(context)
}
@@ -273,7 +247,7 @@ impl HTMLCanvasElement {
) -> Option<DomRoot<WebGLRenderingContext>> {
if let Some(ctx) = self.context() {
return match *ctx {
- CanvasContext::WebGL(ref ctx) => Some(DomRoot::from_ref(ctx)),
+ RenderingContext::WebGL(ref ctx) => Some(DomRoot::from_ref(ctx)),
_ => None,
};
}
@@ -289,7 +263,7 @@ impl HTMLCanvasElement {
attrs,
can_gc,
)?;
- *self.context.borrow_mut() = Some(CanvasContext::WebGL(Dom::from_ref(&*context)));
+ *self.context.borrow_mut() = Some(RenderingContext::WebGL(Dom::from_ref(&*context)));
Some(context)
}
@@ -305,7 +279,7 @@ impl HTMLCanvasElement {
}
if let Some(ctx) = self.context() {
return match *ctx {
- CanvasContext::WebGL2(ref ctx) => Some(DomRoot::from_ref(ctx)),
+ RenderingContext::WebGL2(ref ctx) => Some(DomRoot::from_ref(ctx)),
_ => None,
};
}
@@ -314,7 +288,7 @@ impl HTMLCanvasElement {
let attrs = Self::get_gl_attributes(cx, options)?;
let canvas = HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(DomRoot::from_ref(self));
let context = WebGL2RenderingContext::new(&window, &canvas, size, attrs, can_gc)?;
- *self.context.borrow_mut() = Some(CanvasContext::WebGL2(Dom::from_ref(&*context)));
+ *self.context.borrow_mut() = Some(RenderingContext::WebGL2(Dom::from_ref(&*context)));
Some(context)
}
@@ -327,7 +301,7 @@ impl HTMLCanvasElement {
fn get_or_init_webgpu_context(&self, can_gc: CanGc) -> Option<DomRoot<GPUCanvasContext>> {
if let Some(ctx) = self.context() {
return match *ctx {
- CanvasContext::WebGPU(ref ctx) => Some(DomRoot::from_ref(ctx)),
+ RenderingContext::WebGPU(ref ctx) => Some(DomRoot::from_ref(ctx)),
_ => None,
};
}
@@ -341,7 +315,8 @@ impl HTMLCanvasElement {
.expect("Failed to get WebGPU channel")
.map(|channel| {
let context = GPUCanvasContext::new(&global_scope, self, channel, can_gc);
- *self.context.borrow_mut() = Some(CanvasContext::WebGPU(Dom::from_ref(&*context)));
+ *self.context.borrow_mut() =
+ Some(RenderingContext::WebGPU(Dom::from_ref(&*context)));
context
})
}
@@ -349,8 +324,8 @@ impl HTMLCanvasElement {
/// Gets the base WebGLRenderingContext for WebGL or WebGL 2, if exists.
pub(crate) fn get_base_webgl_context(&self) -> Option<DomRoot<WebGLRenderingContext>> {
match *self.context.borrow() {
- Some(CanvasContext::WebGL(ref context)) => Some(DomRoot::from_ref(context)),
- Some(CanvasContext::WebGL2(ref context)) => Some(context.base_context()),
+ Some(RenderingContext::WebGL(ref context)) => Some(DomRoot::from_ref(context)),
+ Some(RenderingContext::WebGL2(ref context)) => Some(context.base_context()),
_ => None,
}
}
@@ -378,12 +353,7 @@ impl HTMLCanvasElement {
pub(crate) fn get_image_data(&self) -> Option<Snapshot> {
match self.context.borrow().as_ref() {
- Some(CanvasContext::Context2d(context)) => context.get_image_data(),
- Some(CanvasContext::WebGL(context)) => context.get_image_data(),
- Some(CanvasContext::WebGL2(context)) => context.get_image_data(),
- #[cfg(feature = "webgpu")]
- Some(CanvasContext::WebGPU(context)) => context.get_image_data(),
- Some(CanvasContext::Placeholder(context)) => context.get_image_data(),
+ Some(context) => context.get_image_data(),
None => {
let size = self.get_size();
if size.width == 0 || size.height == 0 {
@@ -466,7 +436,7 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
// is set to placeholder, the user agent must throw an "InvalidStateError" DOMException and leave the
// attribute's value unchanged.
fn SetWidth(&self, value: u32, can_gc: CanGc) -> Fallible<()> {
- if let Some(CanvasContext::Placeholder(_)) = *self.context.borrow() {
+ if let Some(RenderingContext::Placeholder(_)) = *self.context.borrow() {
return Err(Error::InvalidState);
}
@@ -485,7 +455,7 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn SetHeight(&self, value: u32, can_gc: CanGc) -> Fallible<()> {
- if let Some(CanvasContext::Placeholder(_)) = *self.context.borrow() {
+ if let Some(RenderingContext::Placeholder(_)) = *self.context.borrow() {
return Err(Error::InvalidState);
}
@@ -506,26 +476,26 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
id: DOMString,
options: HandleValue,
can_gc: CanGc,
- ) -> Fallible<Option<RenderingContext>> {
+ ) -> Fallible<Option<RootedRenderingContext>> {
// Always throw an InvalidState exception when the canvas is in Placeholder mode (See table in the spec).
- if let Some(CanvasContext::Placeholder(_)) = *self.context.borrow() {
+ if let Some(RenderingContext::Placeholder(_)) = *self.context.borrow() {
return Err(Error::InvalidState);
}
Ok(match &*id {
"2d" => self
.get_or_init_2d_context(can_gc)
- .map(RenderingContext::CanvasRenderingContext2D),
+ .map(RootedRenderingContext::CanvasRenderingContext2D),
"webgl" | "experimental-webgl" => self
.get_or_init_webgl_context(cx, options, can_gc)
- .map(RenderingContext::WebGLRenderingContext),
+ .map(RootedRenderingContext::WebGLRenderingContext),
"webgl2" | "experimental-webgl2" => self
.get_or_init_webgl2_context(cx, options, can_gc)
- .map(RenderingContext::WebGL2RenderingContext),
+ .map(RootedRenderingContext::WebGL2RenderingContext),
#[cfg(feature = "webgpu")]
"webgpu" => self
.get_or_init_webgpu_context(can_gc)
- .map(RenderingContext::GPUCanvasContext),
+ .map(RootedRenderingContext::GPUCanvasContext),
_ => None,
})
}
@@ -672,7 +642,8 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
can_gc,
);
// Step 4. Set this canvas element's context mode to placeholder.
- *self.context.borrow_mut() = Some(CanvasContext::Placeholder(offscreen_canvas.as_traced()));
+ *self.context.borrow_mut() =
+ Some(RenderingContext::Placeholder(offscreen_canvas.as_traced()));
// Step 5. Return offscreenCanvas.
Ok(offscreen_canvas)
diff --git a/components/script/dom/htmldetailselement.rs b/components/script/dom/htmldetailselement.rs
index a3e2a05af32..1d48b8e7a97 100644
--- a/components/script/dom/htmldetailselement.rs
+++ b/components/script/dom/htmldetailselement.rs
@@ -178,8 +178,6 @@ impl HTMLDetailsElement {
}
}
shadow_tree.descendants.Assign(slottable_children);
-
- self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
}
fn update_shadow_tree_styles(&self, can_gc: CanGc) {
@@ -214,8 +212,6 @@ impl HTMLDetailsElement {
.implicit_summary
.upcast::<Element>()
.set_string_attribute(&local_name!("style"), implicit_summary_style.into(), can_gc);
-
- self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
}
}
diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs
index b3f222af0da..c2f5ba37c21 100644
--- a/components/script/dom/macros.rs
+++ b/components/script/dom/macros.rs
@@ -719,26 +719,3 @@ macro_rules! handle_potential_webgl_error {
handle_potential_webgl_error!($context, $call, ())
};
}
-
-macro_rules! impl_rare_data (
- ($type:ty) => (
- fn rare_data(&self) -> Ref<Option<Box<$type>>> {
- self.rare_data.borrow()
- }
-
- #[allow(dead_code)]
- fn rare_data_mut(&self) -> RefMut<Option<Box<$type>>> {
- self.rare_data.borrow_mut()
- }
-
- fn ensure_rare_data(&self) -> RefMut<Box<$type>> {
- let mut rare_data = self.rare_data.borrow_mut();
- if rare_data.is_none() {
- *rare_data = Some(Default::default());
- }
- RefMut::map(rare_data, |rare_data| {
- rare_data.as_mut().unwrap()
- })
- }
- );
-);
diff --git a/components/script/dom/messageport.rs b/components/script/dom/messageport.rs
index 85d94c1aa7a..d70d3139b96 100644
--- a/components/script/dom/messageport.rs
+++ b/components/script/dom/messageport.rs
@@ -83,6 +83,20 @@ impl MessagePort {
*self.entangled_port.borrow_mut() = Some(other_id);
}
+ /// <https://html.spec.whatwg.org/multipage/#disentangle>
+ pub(crate) fn disentangle(&self) -> Option<MessagePortId> {
+ // Disentangle initiatorPort and otherPort, so that they are no longer entangled or associated with each other.
+ // Note: called from `disentangle_port` in the global, where the rest happens.
+ self.entangled_port.borrow_mut().take()
+ }
+
+ /// Has the port been disentangled?
+ /// Used when starting the port to fire the `close` event,
+ /// to cover the case of a disentanglement while in transfer.
+ pub(crate) fn disentangled(&self) -> bool {
+ self.entangled_port.borrow().is_none()
+ }
+
pub(crate) fn message_port_id(&self) -> &MessagePortId {
&self.message_port_id
}
@@ -314,20 +328,28 @@ impl MessagePortMethods<crate::DomTypeHolder> for MessagePort {
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-start>
- fn Start(&self) {
+ fn Start(&self, can_gc: CanGc) {
if self.detached.get() {
return;
}
- self.global().start_message_port(self.message_port_id());
+ self.global()
+ .start_message_port(self.message_port_id(), can_gc);
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-close>
- fn Close(&self) {
+ fn Close(&self, can_gc: CanGc) {
if self.detached.get() {
return;
}
+
+ // Set this's [[Detached]] internal slot value to true.
self.detached.set(true);
- self.global().close_message_port(self.message_port_id());
+
+ let global = self.global();
+ global.close_message_port(self.message_port_id());
+
+ // If this is entangled, disentangle it.
+ global.disentangle_port(self, can_gc);
}
/// <https://html.spec.whatwg.org/multipage/#handler-messageport-onmessage>
@@ -340,15 +362,19 @@ impl MessagePortMethods<crate::DomTypeHolder> for MessagePort {
}
/// <https://html.spec.whatwg.org/multipage/#handler-messageport-onmessage>
- fn SetOnmessage(&self, listener: Option<Rc<EventHandlerNonNull>>) {
+ fn SetOnmessage(&self, listener: Option<Rc<EventHandlerNonNull>>, can_gc: CanGc) {
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());
+ self.global()
+ .start_message_port(self.message_port_id(), can_gc);
}
// <https://html.spec.whatwg.org/multipage/#handler-messageport-onmessageerror>
event_handler!(messageerror, GetOnmessageerror, SetOnmessageerror);
+
+ // <https://html.spec.whatwg.org/multipage/#handler-messageport-onclose>
+ event_handler!(close, GetOnclose, SetOnclose);
}
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index b56126076da..1117eff6d3c 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -564,7 +564,17 @@ impl Iterator for QuerySelectorIterator {
}
impl Node {
- impl_rare_data!(NodeRareData);
+ fn rare_data(&self) -> Ref<Option<Box<NodeRareData>>> {
+ self.rare_data.borrow()
+ }
+
+ fn ensure_rare_data(&self) -> RefMut<Box<NodeRareData>> {
+ let mut rare_data = self.rare_data.borrow_mut();
+ if rare_data.is_none() {
+ *rare_data = Some(Default::default());
+ }
+ RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
+ }
/// Returns true if this node is before `other` in the same connected DOM
/// tree.
@@ -1007,24 +1017,25 @@ impl Node {
/// <https://dom.spec.whatwg.org/#dom-childnode-replacewith>
pub(crate) fn replace_with(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
- // Step 1.
- let parent = if let Some(parent) = self.GetParentNode() {
- parent
- } else {
- // Step 2.
+ // Step 1. Let parent be this’s parent.
+ let Some(parent) = self.GetParentNode() else {
+ // Step 2. If parent is null, then return.
return Ok(());
};
- // Step 3.
+
+ // Step 3. Let viableNextSibling be this’s first following sibling not in nodes; otherwise null.
let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
- // Step 4.
+
+ // Step 4. Let node be the result of converting nodes into a node, given nodes and this’s node document.
let node = self
.owner_doc()
.node_from_nodes_and_strings(nodes, can_gc)?;
+
if self.parent_node == Some(&*parent) {
- // Step 5.
+ // Step 5. If this’s parent is parent, replace this with node within parent.
parent.ReplaceChild(&node, self, can_gc)?;
} else {
- // Step 6.
+ // Step 6. Otherwise, pre-insert node into parent before viableNextSibling.
Node::pre_insert(&node, &parent, viable_next_sibling.as_deref(), can_gc)?;
}
Ok(())
@@ -3172,24 +3183,29 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
/// <https://dom.spec.whatwg.org/#concept-node-replace>
fn ReplaceChild(&self, node: &Node, child: &Node, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
- // Step 1.
+ // Step 1. If parent is not a Document, DocumentFragment, or Element node,
+ // then throw a "HierarchyRequestError" DOMException.
match self.type_id() {
NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
},
_ => return Err(Error::HierarchyRequest),
}
- // Step 2.
+ // Step 2. If node is a host-including inclusive ancestor of parent,
+ // then throw a "HierarchyRequestError" DOMException.
if node.is_inclusive_ancestor_of(self) {
return Err(Error::HierarchyRequest);
}
- // Step 3.
+ // Step 3. If child’s parent is not parent, then throw a "NotFoundError" DOMException.
if !self.is_parent_of(child) {
return Err(Error::NotFound);
}
- // Step 4-5.
+ // Step 4. If node is not a DocumentFragment, DocumentType, Element, or CharacterData node,
+ // then throw a "HierarchyRequestError" DOMException.
+ // Step 5. If either node is a Text node and parent is a document,
+ // or node is a doctype and parent is not a document, then throw a "HierarchyRequestError" DOMException.
match node.type_id() {
NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) if self.is::<Document>() => {
return Err(Error::HierarchyRequest);
@@ -3201,7 +3217,8 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
_ => (),
}
- // Step 6.
+ // Step 6. If parent is a document, and any of the statements below, switched on the interface node implements,
+ // are true, then throw a "HierarchyRequestError" DOMException.
if self.is::<Document>() {
match node.type_id() {
// Step 6.1
@@ -3255,7 +3272,8 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
}
}
- // Step 7-8.
+ // Step 7. Let referenceChild be child’s next sibling.
+ // Step 8. If referenceChild is node, then set referenceChild to node’s next sibling.
let child_next_sibling = child.GetNextSibling();
let node_next_sibling = node.GetNextSibling();
let reference_child = if child_next_sibling.as_deref() == Some(node) {
@@ -3264,7 +3282,7 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
child_next_sibling.as_deref()
};
- // Step 9.
+ // Step 9. Let previousSibling be child’s previous sibling.
let previous_sibling = child.GetPreviousSibling();
// NOTE: All existing browsers assume that adoption is performed here, which does not follow the DOM spec.
@@ -3285,7 +3303,7 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
None
};
- // Step 12.
+ // Step 12. Let nodes be node’s children if node is a DocumentFragment node; otherwise « node ».
rooted_vec!(let mut nodes);
let nodes = if node.type_id() ==
NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
@@ -3297,7 +3315,7 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
from_ref(&node)
};
- // Step 13.
+ // Step 13. Insert node into parent before referenceChild with the suppress observers flag set.
Node::insert(
node,
self,
@@ -3306,13 +3324,15 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
can_gc,
);
- // Step 14.
vtable_for(self).children_changed(&ChildrenMutation::replace(
previous_sibling.as_deref(),
&removed_child,
nodes,
reference_child,
));
+
+ // Step 14. Queue a tree mutation record for parent with nodes, removedNodes,
+ // previousSibling, and referenceChild.
let removed = removed_child.map(|r| [r]);
let mutation = LazyCell::new(|| Mutation::ChildList {
added: Some(nodes),
@@ -3323,7 +3343,7 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
MutationObserver::queue_a_mutation_record(self, mutation);
- // Step 15.
+ // Step 15. Return child.
Ok(DomRoot::from_ref(child))
}
diff --git a/components/script/dom/nodelist.rs b/components/script/dom/nodelist.rs
index b349f16a986..1ec2dc3f78b 100644
--- a/components/script/dom/nodelist.rs
+++ b/components/script/dom/nodelist.rs
@@ -175,7 +175,6 @@ impl NodeList {
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
pub(crate) struct ChildrenList {
node: Dom<Node>,
- #[ignore_malloc_size_of = "Defined in rust-mozjs"]
last_visited: MutNullableDom<Node>,
last_index: Cell<u32>,
}
diff --git a/components/script/dom/offscreencanvas.rs b/components/script/dom/offscreencanvas.rs
index aabe5955e12..9947d35f4e0 100644
--- a/components/script/dom/offscreencanvas.rs
+++ b/components/script/dom/offscreencanvas.rs
@@ -9,9 +9,10 @@ use euclid::default::Size2D;
use js::rust::{HandleObject, HandleValue};
use snapshot::Snapshot;
+use crate::canvas_context::{CanvasContext, OffscreenRenderingContext};
use crate::dom::bindings::cell::{DomRefCell, Ref, ref_filter_map};
use crate::dom::bindings::codegen::Bindings::OffscreenCanvasBinding::{
- OffscreenCanvasMethods, OffscreenRenderingContext,
+ OffscreenCanvasMethods, OffscreenRenderingContext as RootedOffscreenRenderingContext,
};
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto};
@@ -23,20 +24,12 @@ use crate::dom::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::offscreencanvasrenderingcontext2d::OffscreenCanvasRenderingContext2D;
use crate::script_runtime::{CanGc, JSContext};
-#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
-#[derive(Clone, JSTraceable, MallocSizeOf)]
-pub(crate) enum OffscreenCanvasContext {
- OffscreenContext2d(Dom<OffscreenCanvasRenderingContext2D>),
- //WebGL(Dom<WebGLRenderingContext>),
- //WebGL2(Dom<WebGL2RenderingContext>),
-}
-
#[dom_struct]
pub(crate) struct OffscreenCanvas {
eventtarget: EventTarget,
width: Cell<u64>,
height: Cell<u64>,
- context: DomRefCell<Option<OffscreenCanvasContext>>,
+ context: DomRefCell<Option<OffscreenRenderingContext>>,
placeholder: Option<Dom<HTMLCanvasElement>>,
}
@@ -77,20 +70,18 @@ impl OffscreenCanvas {
pub(crate) fn origin_is_clean(&self) -> bool {
match *self.context.borrow() {
- Some(OffscreenCanvasContext::OffscreenContext2d(ref context)) => {
- context.origin_is_clean()
- },
+ Some(ref context) => context.origin_is_clean(),
_ => true,
}
}
- pub(crate) fn context(&self) -> Option<Ref<OffscreenCanvasContext>> {
+ pub(crate) fn context(&self) -> Option<Ref<OffscreenRenderingContext>> {
ref_filter_map(self.context.borrow(), |ctx| ctx.as_ref())
}
pub(crate) fn get_image_data(&self) -> Option<Snapshot> {
match self.context.borrow().as_ref() {
- Some(OffscreenCanvasContext::OffscreenContext2d(context)) => context.get_image_data(),
+ Some(context) => context.get_image_data(),
None => {
let size = self.get_size();
if size.width == 0 || size.height == 0 {
@@ -108,13 +99,13 @@ impl OffscreenCanvas {
) -> Option<DomRoot<OffscreenCanvasRenderingContext2D>> {
if let Some(ctx) = self.context() {
return match *ctx {
- OffscreenCanvasContext::OffscreenContext2d(ref ctx) => Some(DomRoot::from_ref(ctx)),
+ OffscreenRenderingContext::Context2d(ref ctx) => Some(DomRoot::from_ref(ctx)),
};
}
let context = OffscreenCanvasRenderingContext2D::new(&self.global(), self, can_gc);
- *self.context.borrow_mut() = Some(OffscreenCanvasContext::OffscreenContext2d(
- Dom::from_ref(&*context),
- ));
+ *self.context.borrow_mut() = Some(OffscreenRenderingContext::Context2d(Dom::from_ref(
+ &*context,
+ )));
Some(context)
}
@@ -125,19 +116,6 @@ impl OffscreenCanvas {
pub(crate) fn placeholder(&self) -> Option<&HTMLCanvasElement> {
self.placeholder.as_deref()
}
-
- pub(crate) fn resize(&self, size: Size2D<u64>) {
- self.width.set(size.width);
- self.height.set(size.height);
-
- if let Some(canvas_context) = self.context() {
- match &*canvas_context {
- OffscreenCanvasContext::OffscreenContext2d(rendering_context) => {
- rendering_context.set_canvas_bitmap_dimensions(self.get_size());
- },
- }
- }
- }
}
impl OffscreenCanvasMethods<crate::DomTypeHolder> for OffscreenCanvas {
@@ -160,11 +138,11 @@ impl OffscreenCanvasMethods<crate::DomTypeHolder> for OffscreenCanvas {
id: DOMString,
_options: HandleValue,
can_gc: CanGc,
- ) -> Fallible<Option<OffscreenRenderingContext>> {
+ ) -> Fallible<Option<RootedOffscreenRenderingContext>> {
match &*id {
"2d" => Ok(self
.get_or_init_2d_context(can_gc)
- .map(OffscreenRenderingContext::OffscreenCanvasRenderingContext2D)),
+ .map(RootedOffscreenRenderingContext::OffscreenCanvasRenderingContext2D)),
/*"webgl" | "experimental-webgl" => self
.get_or_init_webgl_context(cx, options)
.map(OffscreenRenderingContext::WebGLRenderingContext),
@@ -187,11 +165,7 @@ impl OffscreenCanvasMethods<crate::DomTypeHolder> for OffscreenCanvas {
self.width.set(value);
if let Some(canvas_context) = self.context() {
- match &*canvas_context {
- OffscreenCanvasContext::OffscreenContext2d(rendering_context) => {
- rendering_context.set_canvas_bitmap_dimensions(self.get_size());
- },
- }
+ canvas_context.resize();
}
if let Some(canvas) = &self.placeholder {
@@ -209,11 +183,7 @@ impl OffscreenCanvasMethods<crate::DomTypeHolder> for OffscreenCanvas {
self.height.set(value);
if let Some(canvas_context) = self.context() {
- match &*canvas_context {
- OffscreenCanvasContext::OffscreenContext2d(rendering_context) => {
- rendering_context.set_canvas_bitmap_dimensions(self.get_size());
- },
- }
+ canvas_context.resize();
}
if let Some(canvas) = &self.placeholder {
diff --git a/components/script/dom/offscreencanvasrenderingcontext2d.rs b/components/script/dom/offscreencanvasrenderingcontext2d.rs
index b2d0f3201ca..d7ca0e9dc4d 100644
--- a/components/script/dom/offscreencanvasrenderingcontext2d.rs
+++ b/components/script/dom/offscreencanvasrenderingcontext2d.rs
@@ -3,11 +3,10 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::codegen::GenericBindings::CanvasRenderingContext2DBinding::CanvasRenderingContext2D_Binding::CanvasRenderingContext2DMethods;
-use crate::canvas_context::CanvasContext as _;
+use crate::canvas_context::CanvasContext;
use crate::dom::bindings::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanvas;
use canvas_traits::canvas::Canvas2dMsg;
use dom_struct::dom_struct;
-use euclid::default::Size2D;
use snapshot::Snapshot;
use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::{
@@ -64,21 +63,33 @@ impl OffscreenCanvasRenderingContext2D {
reflect_dom_object(boxed, global, can_gc)
}
- pub(crate) fn set_canvas_bitmap_dimensions(&self, size: Size2D<u64>) {
- self.context.set_canvas_bitmap_dimensions(size.cast());
- }
-
pub(crate) fn send_canvas_2d_msg(&self, msg: Canvas2dMsg) {
self.context.send_canvas_2d_msg(msg)
}
+}
- pub(crate) fn origin_is_clean(&self) -> bool {
- self.context.origin_is_clean()
+impl CanvasContext for OffscreenCanvasRenderingContext2D {
+ type ID = <CanvasRenderingContext2D as CanvasContext>::ID;
+
+ fn context_id(&self) -> Self::ID {
+ self.context.context_id()
+ }
+
+ fn canvas(&self) -> HTMLCanvasElementOrOffscreenCanvas {
+ self.context.canvas()
+ }
+
+ fn resize(&self) {
+ self.context.resize()
}
- pub(crate) fn get_image_data(&self) -> Option<Snapshot> {
+ fn get_image_data(&self) -> Option<Snapshot> {
self.context.get_image_data()
}
+
+ fn origin_is_clean(&self) -> bool {
+ self.context.origin_is_clean()
+ }
}
impl OffscreenCanvasRenderingContext2DMethods<crate::DomTypeHolder>
diff --git a/components/script/dom/readablestream.rs b/components/script/dom/readablestream.rs
index 51393ab33ae..4982bfa32e3 100644
--- a/components/script/dom/readablestream.rs
+++ b/components/script/dom/readablestream.rs
@@ -1825,7 +1825,7 @@ impl ReadableStream {
global.note_cross_realm_transform_readable(&cross_realm_transform_readable, port_id);
// Enable port’s port message queue.
- port.Start();
+ port.Start(can_gc);
// Perform ! SetUpReadableStreamDefaultController
controller
@@ -2093,7 +2093,7 @@ impl CrossRealmTransformReadable {
self.controller.close(can_gc);
// Disentangle port.
- global.disentangle_port(port);
+ global.disentangle_port(port, can_gc);
}
// Otherwise, if type is "error",
@@ -2102,7 +2102,7 @@ impl CrossRealmTransformReadable {
self.controller.error(value.handle(), can_gc);
// Disentangle port.
- global.disentangle_port(port);
+ global.disentangle_port(port, can_gc);
}
}
@@ -2129,7 +2129,7 @@ impl CrossRealmTransformReadable {
self.controller.error(rooted_error.handle(), can_gc);
// Disentangle port.
- global.disentangle_port(port);
+ global.disentangle_port(port, can_gc);
}
}
diff --git a/components/script/dom/underlyingsourcecontainer.rs b/components/script/dom/underlyingsourcecontainer.rs
index 541a831693a..4acb58bafef 100644
--- a/components/script/dom/underlyingsourcecontainer.rs
+++ b/components/script/dom/underlyingsourcecontainer.rs
@@ -151,7 +151,7 @@ impl UnderlyingSourceContainer {
let result = port.pack_and_post_message_handling_error("error", reason, can_gc);
// Disentangle port.
- self.global().disentangle_port(port);
+ self.global().disentangle_port(port, can_gc);
let promise = Promise::new(&self.global(), can_gc);
diff --git a/components/script/dom/writablestream.rs b/components/script/dom/writablestream.rs
index 8c2b2434cd2..1b029f592de 100644
--- a/components/script/dom/writablestream.rs
+++ b/components/script/dom/writablestream.rs
@@ -893,7 +893,7 @@ impl WritableStream {
global.note_cross_realm_transform_writable(&cross_realm_transform_writable, port_id);
// Enable port’s port message queue.
- port.Start();
+ port.Start(can_gc);
// Perform ! SetUpWritableStreamDefaultController
controller
@@ -1202,7 +1202,7 @@ impl CrossRealmTransformWritable {
.error_if_needed(cx, rooted_error.handle(), global, can_gc);
// Disentangle port.
- global.disentangle_port(port);
+ global.disentangle_port(port, can_gc);
}
}
diff --git a/components/script/dom/writablestreamdefaultcontroller.rs b/components/script/dom/writablestreamdefaultcontroller.rs
index 301404ffdb2..084165a6892 100644
--- a/components/script/dom/writablestreamdefaultcontroller.rs
+++ b/components/script/dom/writablestreamdefaultcontroller.rs
@@ -173,11 +173,11 @@ impl Callback for TransferBackPressurePromiseReaction {
self.port
.pack_and_post_message_handling_error("chunk", chunk.handle(), can_gc);
- // Disentangle port.
- global.disentangle_port(&self.port);
-
// If result is an abrupt completion,
if let Err(error) = result {
+ // Disentangle port.
+ global.disentangle_port(&self.port, can_gc);
+
// Return a promise rejected with result.[[Value]].
self.result_promise.reject_error(error, can_gc);
} else {
@@ -609,7 +609,7 @@ impl WritableStreamDefaultController {
let result = port.pack_and_post_message_handling_error("error", reason, can_gc);
// Disentangle port.
- global.disentangle_port(port);
+ global.disentangle_port(port, can_gc);
let promise = Promise::new(global, can_gc);
@@ -752,7 +752,7 @@ impl WritableStreamDefaultController {
.expect("Sending close should not fail.");
// Disentangle port.
- global.disentangle_port(port);
+ global.disentangle_port(port, can_gc);
// Return a promise resolved with undefined.
Promise::new_resolved(global, cx, (), can_gc)