diff --git a/components/script/dom/abstractworker.rs b/components/script/dom/abstractworker.rs index 887457e9a3b..5f7131eb0a0 100644 --- a/components/script/dom/abstractworker.rs +++ b/components/script/dom/abstractworker.rs @@ -16,7 +16,7 @@ pub(crate) enum WorkerScriptMsg { /// Message sent through Worker.postMessage DOMMessage { origin: ImmutableOrigin, - data: StructuredSerializedData, + data: Box, }, } diff --git a/components/script/dom/bindings/structuredclone.rs b/components/script/dom/bindings/structuredclone.rs index 077fa1116eb..ee3f50315f4 100644 --- a/components/script/dom/bindings/structuredclone.rs +++ b/components/script/dom/bindings/structuredclone.rs @@ -9,7 +9,7 @@ use std::num::NonZeroU32; use std::os::raw; use std::ptr; -use base::id::{BlobId, MessagePortId, PipelineNamespaceId}; +use base::id::{BlobId, DomPointId, MessagePortId, PipelineNamespaceId}; use js::glue::{ CopyJSStructuredCloneData, DeleteJSAutoStructuredCloneBuffer, GetLengthOfJSStructuredCloneData, NewJSAutoStructuredCloneBuffer, WriteBytesToJSStructuredCloneData, @@ -24,7 +24,7 @@ use js::jsval::UndefinedValue; use js::rust::wrappers::{JS_ReadStructuredClone, JS_WriteStructuredClone}; use js::rust::{CustomAutoRooterGuard, HandleValue, MutableHandleValue}; use script_bindings::conversions::IDLInterface; -use script_traits::serializable::BlobImpl; +use script_traits::serializable::{BlobImpl, DomPoint}; use script_traits::transferable::MessagePortImpl; use script_traits::{ Serializable as SerializableInterface, StructuredSerializedData, @@ -38,6 +38,8 @@ use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::serializable::{IntoStorageKey, Serializable, StorageKey}; use crate::dom::bindings::transferable::{ExtractComponents, IdFromComponents, Transferable}; use crate::dom::blob::Blob; +use crate::dom::dompoint::DOMPoint; +use crate::dom::dompointreadonly::DOMPointReadOnly; use crate::dom::globalscope::GlobalScope; use crate::dom::messageport::MessagePort; use crate::realms::{AlreadyInRealm, InRealm, enter_realm}; @@ -54,6 +56,8 @@ pub(super) enum StructuredCloneTags { DomBlob = 0xFFFF8001, MessagePort = 0xFFFF8002, Principals = 0xFFFF8003, + DomPointReadOnly = 0xFFFF8004, + DomPoint = 0xFFFF8005, Max = 0xFFFFFFFF, } @@ -61,6 +65,8 @@ impl From for StructuredCloneTags { fn from(v: SerializableInterface) -> Self { match v { SerializableInterface::Blob => StructuredCloneTags::DomBlob, + SerializableInterface::DomPointReadOnly => StructuredCloneTags::DomPointReadOnly, + SerializableInterface::DomPoint => StructuredCloneTags::DomPoint, } } } @@ -83,6 +89,8 @@ fn reader_for_type( ) -> *mut JSObject { match val { SerializableInterface::Blob => read_object::, + SerializableInterface::DomPointReadOnly => read_object::, + SerializableInterface::DomPoint => read_object::, } } @@ -214,6 +222,8 @@ type SerializeOperation = unsafe fn( fn serialize_for_type(val: SerializableInterface) -> SerializeOperation { match val { SerializableInterface::Blob => try_serialize::, + SerializableInterface::DomPointReadOnly => try_serialize::, + SerializableInterface::DomPoint => try_serialize::, } } @@ -465,6 +475,9 @@ pub(crate) enum StructuredData<'a> { pub(crate) struct StructuredDataReader { /// A map of deserialized blobs, stored temporarily here to keep them rooted. pub(crate) blobs: Option>>, + /// A map of deserialized points, stored temporarily here to keep them rooted. + pub(crate) points_read_only: Option>>, + pub(crate) dom_points: Option>>, /// A vec of transfer-received DOM ports, /// to be made available to script through a message event. pub(crate) message_ports: Option>>, @@ -476,12 +489,17 @@ pub(crate) struct StructuredDataReader { /// used as part of the "deserialize" steps of blobs, /// to produce the DOM blobs stored in `blobs` above. pub(crate) blob_impls: Option>, + /// A map of serialized points. + pub(crate) points: Option>, } /// A data holder for transferred and serialized objects. +#[derive(Default)] pub(crate) struct StructuredDataWriter { /// Transferred ports. pub(crate) ports: Option>, + /// Serialized points. + pub(crate) points: Option>, /// Serialized blobs. pub(crate) blobs: Option>, } @@ -497,10 +515,7 @@ pub(crate) fn write( if let Some(transfer) = transfer { transfer.to_jsval(*cx, val.handle_mut()); } - let mut sc_writer = StructuredDataWriter { - ports: None, - blobs: None, - }; + let mut sc_writer = StructuredDataWriter::default(); let sc_writer_ptr = &mut sc_writer as *mut _; let scbuf = NewJSAutoStructuredCloneBuffer( @@ -537,6 +552,7 @@ pub(crate) fn write( let data = StructuredSerializedData { serialized: data, ports: sc_writer.ports.take(), + points: sc_writer.points.take(), blobs: sc_writer.blobs.take(), }; @@ -556,8 +572,11 @@ pub(crate) fn read( let mut sc_reader = StructuredDataReader { blobs: None, message_ports: None, + points_read_only: None, + dom_points: None, port_impls: data.ports.take(), blob_impls: data.blobs.take(), + points: data.points.take(), }; let sc_reader_ptr = &mut sc_reader as *mut _; unsafe { diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index 605bc3dcde9..cc426494171 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -564,7 +564,8 @@ impl DedicatedWorkerGlobalScope { let target = self.upcast(); let _ac = enter_realm(self); rooted!(in(*scope.get_cx()) let mut message = UndefinedValue()); - if let Ok(ports) = structuredclone::read(scope.upcast(), data, message.handle_mut()) + if let Ok(ports) = + structuredclone::read(scope.upcast(), *data, message.handle_mut()) { MessageEvent::dispatch_jsval( target, diff --git a/components/script/dom/dompoint.rs b/components/script/dom/dompoint.rs index 4e90ffa3db6..84b02e6f4c4 100644 --- a/components/script/dom/dompoint.rs +++ b/components/script/dom/dompoint.rs @@ -2,14 +2,20 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use std::collections::HashMap; + +use base::id::DomPointId; use dom_struct::dom_struct; use js::rust::HandleObject; +use script_traits::serializable::DomPoint; use crate::dom::bindings::codegen::Bindings::DOMPointBinding::{DOMPointInit, DOMPointMethods}; use crate::dom::bindings::codegen::Bindings::DOMPointReadOnlyBinding::DOMPointReadOnlyMethods; use crate::dom::bindings::error::Fallible; use crate::dom::bindings::reflector::reflect_dom_object_with_proto; use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::serializable::{Serializable, StorageKey}; +use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader}; use crate::dom::dompointreadonly::{DOMPointReadOnly, DOMPointWriteMethods}; use crate::dom::globalscope::GlobalScope; use crate::script_runtime::CanGc; @@ -124,3 +130,49 @@ impl DOMPointMethods for DOMPoint { self.point.SetW(value); } } + +impl Serializable for DOMPoint { + type Id = DomPointId; + type Data = DomPoint; + + fn serialize(&self) -> Result<(Self::Id, Self::Data), ()> { + let serialized = DomPoint { + x: self.X(), + y: self.Y(), + z: self.Z(), + w: self.W(), + }; + Ok((DomPointId::new(), serialized)) + } + + fn deserialize( + owner: &GlobalScope, + serialized: Self::Data, + can_gc: CanGc, + ) -> Result, ()> + where + Self: Sized, + { + Ok(Self::new( + owner, + serialized.x, + serialized.y, + serialized.z, + serialized.w, + can_gc, + )) + } + + fn serialized_storage(data: StructuredData<'_>) -> &mut Option> { + match data { + StructuredData::Reader(reader) => &mut reader.points, + StructuredData::Writer(writer) => &mut writer.points, + } + } + + fn deserialized_storage( + reader: &mut StructuredDataReader, + ) -> &mut Option>> { + &mut reader.dom_points + } +} diff --git a/components/script/dom/dompointreadonly.rs b/components/script/dom/dompointreadonly.rs index d437c470cc9..fed82bd9055 100644 --- a/components/script/dom/dompointreadonly.rs +++ b/components/script/dom/dompointreadonly.rs @@ -3,15 +3,21 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use std::cell::Cell; +use std::collections::HashMap; +use std::num::NonZeroU32; +use base::id::{DomPointId, DomPointIndex, PipelineNamespaceId}; use dom_struct::dom_struct; use js::rust::HandleObject; +use script_traits::serializable::DomPoint; use crate::dom::bindings::codegen::Bindings::DOMPointBinding::DOMPointInit; use crate::dom::bindings::codegen::Bindings::DOMPointReadOnlyBinding::DOMPointReadOnlyMethods; use crate::dom::bindings::error::Fallible; use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto}; use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::serializable::{IntoStorageKey, Serializable, StorageKey}; +use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader}; use crate::dom::globalscope::GlobalScope; use crate::script_runtime::CanGc; @@ -134,3 +140,70 @@ impl DOMPointWriteMethods for DOMPointReadOnly { self.w.set(value); } } + +impl Serializable for DOMPointReadOnly { + type Id = DomPointId; + type Data = DomPoint; + + fn serialize(&self) -> Result<(Self::Id, Self::Data), ()> { + let serialized = DomPoint { + x: self.x.get(), + y: self.y.get(), + z: self.z.get(), + w: self.w.get(), + }; + Ok((DomPointId::new(), serialized)) + } + + fn deserialize( + owner: &GlobalScope, + serialized: Self::Data, + can_gc: CanGc, + ) -> Result, ()> + where + Self: Sized, + { + Ok(Self::new( + owner, + serialized.x, + serialized.y, + serialized.z, + serialized.w, + can_gc, + )) + } + + fn serialized_storage(data: StructuredData<'_>) -> &mut Option> { + match data { + StructuredData::Reader(r) => &mut r.points, + StructuredData::Writer(w) => &mut w.points, + } + } + + fn deserialized_storage( + reader: &mut StructuredDataReader, + ) -> &mut Option>> { + &mut reader.points_read_only + } +} + +impl From for DomPointId { + fn from(storage_key: StorageKey) -> DomPointId { + let namespace_id = PipelineNamespaceId(storage_key.name_space); + let index = DomPointIndex( + NonZeroU32::new(storage_key.index).expect("Deserialized point index is zero"), + ); + + DomPointId { + namespace_id, + index, + } + } +} + +impl IntoStorageKey for DomPointId { + fn into_storage_key(self) -> StorageKey { + let DomPointIndex(index) = self.index; + StorageKey::new(self.namespace_id, index) + } +} diff --git a/components/script/dom/history.rs b/components/script/dom/history.rs index 7034c15f026..b4b6e44890f 100644 --- a/components/script/dom/history.rs +++ b/components/script/dom/history.rs @@ -123,8 +123,7 @@ impl History { Some(data) => { let data = StructuredSerializedData { serialized: data, - ports: None, - blobs: None, + ..Default::default() }; rooted!(in(*GlobalScope::get_cx()) let mut state = UndefinedValue()); if structuredclone::read(self.window.as_global_scope(), data, state.handle_mut()) diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs index 9b12561388f..f52582b99ee 100644 --- a/components/script/dom/serviceworkerglobalscope.rs +++ b/components/script/dom/serviceworkerglobalscope.rs @@ -443,7 +443,8 @@ impl ServiceWorkerGlobalScope { let target = self.upcast(); let _ac = enter_realm(scope); rooted!(in(*scope.get_cx()) let mut message = UndefinedValue()); - if let Ok(ports) = structuredclone::read(scope.upcast(), data, message.handle_mut()) + if let Ok(ports) = + structuredclone::read(scope.upcast(), *data, message.handle_mut()) { ExtendableMessageEvent::dispatch_jsval( target, diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index 278fd541c0b..34fc30ce0e5 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -148,7 +148,7 @@ impl Worker { address, WorkerScriptMsg::DOMMessage { origin: self.global().origin().immutable().clone(), - data, + data: Box::new(data), }, )); Ok(()) diff --git a/components/script/serviceworker_manager.rs b/components/script/serviceworker_manager.rs index 7ad4204f9fb..dba412d9a42 100644 --- a/components/script/serviceworker_manager.rs +++ b/components/script/serviceworker_manager.rs @@ -64,7 +64,10 @@ impl ServiceWorker { fn forward_dom_message(&self, msg: DOMMessage) { let DOMMessage { origin, data } = msg; let _ = self.sender.send(ServiceWorkerScriptMsg::CommonWorker( - WorkerScriptMsg::DOMMessage { origin, data }, + WorkerScriptMsg::DOMMessage { + origin, + data: Box::new(data), + }, )); } diff --git a/components/shared/base/id.rs b/components/shared/base/id.rs index acfc6493900..6a9729c45c5 100644 --- a/components/shared/base/id.rs +++ b/components/shared/base/id.rs @@ -195,6 +195,7 @@ impl PipelineNamespace { namespace_id_method! {next_service_worker_registration_id, ServiceWorkerRegistrationId, self, ServiceWorkerRegistrationIndex} namespace_id_method! {next_blob_id, BlobId, self, BlobIndex} + namespace_id_method! {next_dom_point_id, DomPointId, self, DomPointIndex} } thread_local!(pub static PIPELINE_NAMESPACE: Cell> = const { Cell::new(None) }); @@ -411,6 +412,19 @@ impl BlobId { } } +namespace_id! {DomPointId, DomPointIndex, "DomPoint"} + +impl DomPointId { + pub fn new() -> DomPointId { + PIPELINE_NAMESPACE.with(|tls| { + let mut namespace = tls.get().expect("No namespace set for this thread!"); + let next_point_id = namespace.next_dom_point_id(); + tls.set(Some(namespace)); + next_point_id + }) + } +} + namespace_id! {HistoryStateId, HistoryStateIndex, "HistoryState"} impl HistoryStateId { diff --git a/components/shared/script/lib.rs b/components/shared/script/lib.rs index dfb7484d3bb..8f3cc4d95e2 100644 --- a/components/shared/script/lib.rs +++ b/components/shared/script/lib.rs @@ -21,8 +21,8 @@ use std::sync::Arc; use background_hang_monitor_api::BackgroundHangMonitorRegister; use base::cross_process_instant::CrossProcessInstant; use base::id::{ - BlobId, BrowsingContextId, HistoryStateId, MessagePortId, PipelineId, PipelineNamespaceId, - WebViewId, + BlobId, BrowsingContextId, DomPointId, HistoryStateId, MessagePortId, PipelineId, + PipelineNamespaceId, WebViewId, }; #[cfg(feature = "bluetooth")] use bluetooth_traits::BluetoothRequest; @@ -64,7 +64,7 @@ pub use crate::script_msg::{ DOMMessage, IFrameSizeMsg, Job, JobError, JobResult, JobResultValue, JobType, SWManagerMsg, SWManagerSenders, ScopeThings, ScriptMsg, ServiceWorkerMsg, TouchEventResult, }; -use crate::serializable::BlobImpl; +use crate::serializable::{BlobImpl, DomPoint}; use crate::transferable::MessagePortImpl; /// The origin where a given load was initiated. @@ -648,12 +648,14 @@ impl ScriptToConstellationChan { /// A data-holder for serialized data and transferred objects. /// -#[derive(Debug, Deserialize, MallocSizeOf, Serialize)] +#[derive(Debug, Default, Deserialize, MallocSizeOf, Serialize)] pub struct StructuredSerializedData { /// Data serialized by SpiderMonkey. pub serialized: Vec, /// Serialized in a structured callback, pub blobs: Option>, + /// Serialized point objects. + pub points: Option>, /// Transferred objects. pub ports: Option>, } @@ -678,12 +680,20 @@ where pub enum Serializable { /// The `Blob` interface. Blob, + /// The `DOMPoint` interface. + DomPoint, + /// The `DOMPointReadOnly` interface. + DomPointReadOnly, } impl Serializable { fn clone_values(&self) -> fn(&StructuredSerializedData, &mut StructuredSerializedData) { match self { Serializable::Blob => StructuredSerializedData::clone_all_of_type::, + Serializable::DomPointReadOnly => { + StructuredSerializedData::clone_all_of_type:: + }, + Serializable::DomPoint => StructuredSerializedData::clone_all_of_type::, } } } @@ -737,9 +747,7 @@ impl StructuredSerializedData { let mut cloned = StructuredSerializedData { serialized, - blobs: None, - // Ports cannot be broadcast. - ports: None, + ..Default::default() }; for serializable in Serializable::iter() { diff --git a/components/shared/script/serializable.rs b/components/shared/script/serializable.rs index 8e9f9f5b3da..5d89c622bee 100644 --- a/components/shared/script/serializable.rs +++ b/components/shared/script/serializable.rs @@ -11,7 +11,7 @@ use std::cell::RefCell; use std::path::PathBuf; -use base::id::BlobId; +use base::id::{BlobId, DomPointId}; use malloc_size_of_derive::MallocSizeOf; use net_traits::filemanager_thread::RelativePos; use serde::{Deserialize, Serialize}; @@ -182,3 +182,36 @@ impl BlobImpl { &mut self.blob_data } } + +#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)] +/// A serializable version of the DOMPoint/DOMPointReadOnly interface. +pub struct DomPoint { + /// The x coordinate. + pub x: f64, + /// The y coordinate. + pub y: f64, + /// The z coordinate. + pub z: f64, + /// The w coordinate. + pub w: f64, +} + +impl crate::BroadcastClone for DomPoint { + type Id = DomPointId; + + fn source( + data: &crate::StructuredSerializedData, + ) -> &Option> { + &data.points + } + + fn destination( + data: &mut crate::StructuredSerializedData, + ) -> &mut Option> { + &mut data.points + } + + fn clone_for_broadcast(&self) -> Option { + Some(self.clone()) + } +} diff --git a/tests/wpt/meta/css/geometry/structured-serialization.html.ini b/tests/wpt/meta/css/geometry/structured-serialization.html.ini index 4c5e6ea2aa0..2b817e6c20b 100644 --- a/tests/wpt/meta/css/geometry/structured-serialization.html.ini +++ b/tests/wpt/meta/css/geometry/structured-serialization.html.ini @@ -1,28 +1,4 @@ [structured-serialization.html] - [DOMPointReadOnly clone: basic] - expected: FAIL - - [DOMPointReadOnly clone: custom property] - expected: FAIL - - [DOMPointReadOnly clone: throwing getters] - expected: FAIL - - [DOMPointReadOnly clone: non-initial values] - expected: FAIL - - [DOMPoint clone: basic] - expected: FAIL - - [DOMPoint clone: custom property] - expected: FAIL - - [DOMPoint clone: throwing getters] - expected: FAIL - - [DOMPoint clone: non-initial values] - expected: FAIL - [DOMRectReadOnly clone: basic] expected: FAIL