aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/bindings/error.rs1
-rw-r--r--components/script/dom/bindings/serializable.rs37
-rw-r--r--components/script/dom/bindings/structuredclone.rs102
-rw-r--r--components/script/dom/bindings/transferable.rs29
-rw-r--r--components/script/dom/blob.rs41
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs16
-rw-r--r--components/script/dom/cssstylesheet.rs30
-rw-r--r--components/script/dom/document.rs30
-rw-r--r--components/script/dom/domexception.rs48
-rw-r--r--components/script/dom/dompoint.rs20
-rw-r--r--components/script/dom/dompointreadonly.rs42
-rw-r--r--components/script/dom/globalscope.rs19
-rw-r--r--components/script/dom/htmlcanvaselement.rs78
-rw-r--r--components/script/dom/messageport.rs32
-rw-r--r--components/script/dom/node.rs1
-rw-r--r--components/script/dom/offscreencanvas.rs27
-rw-r--r--components/script/dom/offscreencanvasrenderingcontext2d.rs6
-rw-r--r--components/script/dom/readablestream.rs16
-rw-r--r--components/script/dom/response.rs248
-rw-r--r--components/script/dom/webgl2renderingcontext.rs11
-rw-r--r--components/script/dom/webglrenderingcontext.rs36
-rw-r--r--components/script/dom/webgpu/gpucanvascontext.rs9
-rw-r--r--components/script/dom/window.rs34
-rw-r--r--components/script/dom/writablestream.rs14
-rw-r--r--components/script/dom/writablestreamdefaultcontroller.rs2
25 files changed, 427 insertions, 502 deletions
diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs
index b0fd301df6a..f5bd03cd8d7 100644
--- a/components/script/dom/bindings/error.rs
+++ b/components/script/dom/bindings/error.rs
@@ -93,6 +93,7 @@ pub(crate) fn throw_dom_exception(
Error::NotReadable => DOMErrorName::NotReadableError,
Error::Data => DOMErrorName::DataError,
Error::Operation => DOMErrorName::OperationError,
+ Error::NotAllowed => DOMErrorName::NotAllowedError,
Error::Type(message) => unsafe {
assert!(!JS_IsExceptionPending(*cx));
throw_type_error(*cx, &message);
diff --git a/components/script/dom/bindings/serializable.rs b/components/script/dom/bindings/serializable.rs
index b791b0ebc1a..d0e851b4799 100644
--- a/components/script/dom/bindings/serializable.rs
+++ b/components/script/dom/bindings/serializable.rs
@@ -6,13 +6,12 @@
//! (<https://html.spec.whatwg.org/multipage/#serializable-objects>).
use std::collections::HashMap;
-use std::num::NonZeroU32;
-use base::id::PipelineNamespaceId;
+use base::id::{Index, NamespaceIndex, PipelineNamespaceId};
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::DomRoot;
-use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader};
+use crate::dom::bindings::structuredclone::StructuredData;
use crate::dom::globalscope::GlobalScope;
use crate::script_runtime::CanGc;
@@ -25,9 +24,9 @@ pub(crate) struct StorageKey {
}
impl StorageKey {
- pub(crate) fn new(name_space: PipelineNamespaceId, index: NonZeroU32) -> StorageKey {
- let name_space = name_space.0.to_ne_bytes();
- let index = index.get().to_ne_bytes();
+ pub(crate) fn new<T>(index: NamespaceIndex<T>) -> StorageKey {
+ let name_space = index.namespace_id.0.to_ne_bytes();
+ let index = index.index.0.get().to_ne_bytes();
StorageKey {
index: u32::from_ne_bytes(index),
name_space: u32::from_ne_bytes(name_space),
@@ -35,11 +34,13 @@ impl StorageKey {
}
}
-pub(crate) trait IntoStorageKey
-where
- Self: Sized,
-{
- fn into_storage_key(self) -> StorageKey;
+impl<T> From<StorageKey> for NamespaceIndex<T> {
+ fn from(key: StorageKey) -> NamespaceIndex<T> {
+ NamespaceIndex {
+ namespace_id: PipelineNamespaceId(key.name_space),
+ index: Index::new(key.index).expect("Index must not be zero"),
+ }
+ }
}
/// Interface for serializable platform objects.
@@ -48,11 +49,11 @@ pub(crate) trait Serializable: DomObject
where
Self: Sized,
{
- type Id: Copy + Eq + std::hash::Hash + IntoStorageKey + From<StorageKey>;
+ type Index: Copy + Eq + std::hash::Hash;
type Data;
/// <https://html.spec.whatwg.org/multipage/#serialization-steps>
- fn serialize(&self) -> Result<(Self::Id, Self::Data), ()>;
+ fn serialize(&self) -> Result<(NamespaceIndex<Self::Index>, Self::Data), ()>;
/// <https://html.spec.whatwg.org/multipage/#deserialization-steps>
fn deserialize(
owner: &GlobalScope,
@@ -64,11 +65,7 @@ where
/// Returns the field of [StructuredDataReader]/[StructuredDataWriter] that
/// should be used to read/store serialized instances of this type.
- fn serialized_storage(data: StructuredData<'_>) -> &mut Option<HashMap<Self::Id, Self::Data>>;
-
- /// Returns the field of [StructuredDataReader] that should be used to store
- /// deserialized instances of this type.
- fn deserialized_storage(
- reader: &mut StructuredDataReader,
- ) -> &mut Option<HashMap<StorageKey, DomRoot<Self>>>;
+ fn serialized_storage<'a>(
+ data: StructuredData<'a, '_>,
+ ) -> &'a mut Option<HashMap<NamespaceIndex<Self::Index>, Self::Data>>;
}
diff --git a/components/script/dom/bindings/structuredclone.rs b/components/script/dom/bindings/structuredclone.rs
index ebd881a04f5..c9a49ba00c9 100644
--- a/components/script/dom/bindings/structuredclone.rs
+++ b/components/script/dom/bindings/structuredclone.rs
@@ -6,22 +6,24 @@
use std::collections::HashMap;
use std::ffi::CStr;
-use std::num::NonZeroU32;
use std::os::raw;
use std::ptr;
-use base::id::{BlobId, DomExceptionId, DomPointId, MessagePortId, PipelineNamespaceId};
+use base::id::{
+ BlobId, DomExceptionId, DomPointId, Index, MessagePortId, NamespaceIndex, PipelineNamespaceId,
+};
use constellation_traits::{
BlobImpl, DomException, DomPoint, MessagePortImpl, Serializable as SerializableInterface,
StructuredSerializedData, Transferrable as TransferrableInterface,
};
+use js::gc::RootedVec;
use js::glue::{
CopyJSStructuredCloneData, DeleteJSAutoStructuredCloneBuffer, GetLengthOfJSStructuredCloneData,
NewJSAutoStructuredCloneBuffer, WriteBytesToJSStructuredCloneData,
};
use js::jsapi::{
- CloneDataPolicy, HandleObject as RawHandleObject, JS_ClearPendingException, JS_ReadUint32Pair,
- JS_STRUCTURED_CLONE_VERSION, JS_WriteUint32Pair, JSContext, JSObject,
+ CloneDataPolicy, HandleObject as RawHandleObject, Heap, JS_ClearPendingException,
+ JS_ReadUint32Pair, JS_STRUCTURED_CLONE_VERSION, JS_WriteUint32Pair, JSContext, JSObject,
JSStructuredCloneCallbacks, JSStructuredCloneReader, JSStructuredCloneWriter,
MutableHandleObject as RawMutableHandleObject, StructuredCloneScope, TransferableOwnership,
};
@@ -34,8 +36,8 @@ use strum::IntoEnumIterator;
use crate::dom::bindings::conversions::{ToJSValConvertible, root_from_object};
use crate::dom::bindings::error::{Error, Fallible};
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::bindings::serializable::{Serializable, StorageKey};
+use crate::dom::bindings::transferable::Transferable;
use crate::dom::blob::Blob;
use crate::dom::dompoint::DOMPoint;
use crate::dom::dompointreadonly::DOMPointReadOnly;
@@ -92,7 +94,7 @@ fn reader_for_type(
) -> unsafe fn(
&GlobalScope,
*mut JSStructuredCloneReader,
- &mut StructuredDataReader,
+ &mut StructuredDataReader<'_>,
CanGc,
) -> *mut JSObject {
match val {
@@ -106,7 +108,7 @@ fn reader_for_type(
unsafe fn read_object<T: Serializable>(
owner: &GlobalScope,
r: *mut JSStructuredCloneReader,
- sc_reader: &mut StructuredDataReader,
+ sc_reader: &mut StructuredDataReader<'_>,
can_gc: CanGc,
) -> *mut JSObject {
let mut name_space: u32 = 0;
@@ -120,7 +122,7 @@ unsafe fn read_object<T: Serializable>(
// 1. Re-build the key for the storage location
// of the serialized object.
- let id = T::Id::from(storage_key);
+ let id: NamespaceIndex<T::Index> = storage_key.into();
// 2. Get the transferred object from its storage, using the key.
let objects = T::serialized_storage(StructuredData::Reader(sc_reader));
@@ -135,9 +137,8 @@ unsafe fn read_object<T: Serializable>(
}
if let Ok(obj) = T::deserialize(owner, serialized, can_gc) {
- let destination = T::deserialized_storage(sc_reader).get_or_insert_with(HashMap::new);
let reflector = obj.reflector().get_jsobject().get();
- destination.insert(storage_key, obj);
+ sc_reader.roots.push(Heap::boxed(reflector));
return reflector;
}
warn!("Reading structured data failed in {:?}.", owner.get_url());
@@ -155,7 +156,7 @@ unsafe fn write_object<T: Serializable>(
let objects = T::serialized_storage(StructuredData::Writer(sc_writer))
.get_or_insert_with(HashMap::new);
objects.insert(new_id, serialized);
- let storage_key = new_id.into_storage_key();
+ let storage_key = StorageKey::new(new_id);
assert!(JS_WriteUint32Pair(
w,
@@ -190,7 +191,7 @@ unsafe extern "C" fn read_callback(
"tag should be higher than StructuredCloneTags::Min"
);
- let sc_reader = &mut *(closure as *mut StructuredDataReader);
+ let sc_reader = &mut *(closure as *mut StructuredDataReader<'_>);
let in_realm_proof = AlreadyInRealm::assert_for_cx(SafeJSContext::from_ptr(cx));
let global = GlobalScope::from_context(cx, InRealm::Already(&in_realm_proof));
for serializable in SerializableInterface::iter() {
@@ -258,7 +259,8 @@ unsafe extern "C" fn write_callback(
fn receiver_for_type(
val: TransferrableInterface,
-) -> fn(&GlobalScope, &mut StructuredDataReader, u64, RawMutableHandleObject) -> Result<(), ()> {
+) -> fn(&GlobalScope, &mut StructuredDataReader<'_>, u64, RawMutableHandleObject) -> Result<(), ()>
+{
match val {
TransferrableInterface::MessagePort => receive_object::<MessagePort>,
TransferrableInterface::ReadableStream => receive_object::<ReadableStream>,
@@ -268,7 +270,7 @@ fn receiver_for_type(
fn receive_object<T: Transferable>(
owner: &GlobalScope,
- sc_reader: &mut StructuredDataReader,
+ sc_reader: &mut StructuredDataReader<'_>,
extra_data: u64,
return_object: RawMutableHandleObject,
) -> Result<(), ()> {
@@ -282,13 +284,13 @@ fn receive_object<T: Transferable>(
.try_into()
.expect("name_space to be a slice of four."),
));
- let id = <T::Id as IdFromComponents>::from(
+ let id: NamespaceIndex<T::Index> = NamespaceIndex {
namespace_id,
- NonZeroU32::new(u32::from_ne_bytes(
+ index: Index::new(u32::from_ne_bytes(
index.try_into().expect("index to be a slice of four."),
))
.expect("Index to be non-zero"),
- );
+ };
// 2. Get the transferred object from its storage, using the key.
let storage = T::serialized_storage(StructuredData::Reader(sc_reader));
@@ -304,13 +306,12 @@ fn receive_object<T: Transferable>(
);
};
- if let Ok(received) = T::transfer_receive(owner, id, serialized) {
- return_object.set(received.reflector().rootable().get());
- let storage = T::deserialized_storage(sc_reader).get_or_insert_with(Vec::new);
- storage.push(received);
- return Ok(());
- }
- Err(())
+ let Ok(received) = T::transfer_receive(owner, id, serialized) else {
+ return Err(());
+ };
+ return_object.set(received.reflector().rootable().get());
+ sc_reader.roots.push(Heap::boxed(return_object.get()));
+ Ok(())
}
unsafe extern "C" fn read_transfer_callback(
@@ -323,7 +324,7 @@ unsafe extern "C" fn read_transfer_callback(
closure: *mut raw::c_void,
return_object: RawMutableHandleObject,
) -> bool {
- let sc_reader = &mut *(closure as *mut StructuredDataReader);
+ let sc_reader = &mut *(closure as *mut StructuredDataReader<'_>);
let in_realm_proof = AlreadyInRealm::assert_for_cx(SafeJSContext::from_ptr(cx));
let owner = GlobalScope::from_context(cx, InRealm::Already(&in_realm_proof));
@@ -356,11 +357,10 @@ unsafe fn try_transfer<T: Transferable + IDLInterface>(
.get_or_insert_with(HashMap::new);
objects.insert(id, object);
- let (PipelineNamespaceId(name_space), index) = id.components();
- let index = index.get();
+ let index = id.index.0.get();
let mut big: [u8; 8] = [0; 8];
- let name_space = name_space.to_ne_bytes();
+ let name_space = id.namespace_id.0.to_ne_bytes();
let index = index.to_ne_bytes();
let (left, right) = big.split_at_mut(4);
@@ -489,8 +489,8 @@ static STRUCTURED_CLONE_CALLBACKS: JSStructuredCloneCallbacks = JSStructuredClon
sabCloned: Some(sab_cloned_callback),
};
-pub(crate) enum StructuredData<'a> {
- Reader(&'a mut StructuredDataReader),
+pub(crate) enum StructuredData<'a, 'b> {
+ Reader(&'a mut StructuredDataReader<'b>),
Writer(&'a mut StructuredDataWriter),
}
@@ -503,19 +503,11 @@ pub(crate) struct DOMErrorRecord {
/// Reader and writer structs for results from, and inputs to, structured-data read/write operations.
/// <https://html.spec.whatwg.org/multipage/#safe-passing-of-structured-data>
#[repr(C)]
-pub(crate) struct StructuredDataReader {
+pub(crate) struct StructuredDataReader<'a> {
/// A struct of error message.
- pub(crate) errors: DOMErrorRecord,
- /// A map of deserialized blobs, stored temporarily here to keep them rooted.
- pub(crate) blobs: Option<HashMap<StorageKey, DomRoot<Blob>>>,
- /// A map of deserialized points, stored temporarily here to keep them rooted.
- pub(crate) points_read_only: Option<HashMap<StorageKey, DomRoot<DOMPointReadOnly>>>,
- pub(crate) dom_points: Option<HashMap<StorageKey, DomRoot<DOMPoint>>>,
- /// A map of deserialized exceptions, stored temporarily here to keep them rooted.
- pub(crate) dom_exceptions: Option<HashMap<StorageKey, DomRoot<DOMException>>>,
- /// A vec of transfer-received DOM ports,
- /// to be made available to script through a message event.
- pub(crate) message_ports: Option<Vec<DomRoot<MessagePort>>>,
+ errors: DOMErrorRecord,
+ /// Rooted copies of every deserialized object to ensure they are not garbage collected.
+ roots: RootedVec<'a, Box<Heap<*mut JSObject>>>,
/// A map of port implementations,
/// used as part of the "transfer-receiving" steps of ports,
/// to produce the DOM ports stored in `message_ports` above.
@@ -528,12 +520,6 @@ pub(crate) struct StructuredDataReader {
pub(crate) points: Option<HashMap<DomPointId, DomPoint>>,
/// A map of serialized exceptions.
pub(crate) exceptions: Option<HashMap<DomExceptionId, DomException>>,
-
- /// <https://streams.spec.whatwg.org/#rs-transfer>
- pub(crate) readable_streams: Option<Vec<DomRoot<ReadableStream>>>,
-
- /// <https://streams.spec.whatwg.org/#ws-transfer>
- pub(crate) writable_streams: Option<Vec<DomRoot<WritableStream>>>,
}
/// A data holder for transferred and serialized objects.
@@ -618,19 +604,14 @@ pub(crate) fn read(
) -> Fallible<Vec<DomRoot<MessagePort>>> {
let cx = GlobalScope::get_cx();
let _ac = enter_realm(global);
+ rooted_vec!(let mut roots);
let mut sc_reader = StructuredDataReader {
- blobs: None,
- message_ports: None,
- points_read_only: None,
- dom_points: None,
- dom_exceptions: None,
+ roots,
port_impls: data.ports.take(),
blob_impls: data.blobs.take(),
points: data.points.take(),
exceptions: data.exceptions.take(),
errors: DOMErrorRecord { message: None },
- readable_streams: None,
- writable_streams: None,
};
let sc_reader_ptr = &mut sc_reader as *mut _;
unsafe {
@@ -666,8 +647,15 @@ pub(crate) fn read(
DeleteJSAutoStructuredCloneBuffer(scbuf);
+ let mut message_ports = vec![];
+ for reflector in sc_reader.roots.iter() {
+ let Ok(message_port) = root_from_object::<MessagePort>(reflector.get(), *cx) else {
+ continue;
+ };
+ message_ports.push(message_port);
+ }
// Any transfer-received port-impls should have been taken out.
assert!(sc_reader.port_impls.is_none());
- Ok(sc_reader.message_ports.take().unwrap_or_default())
+ Ok(message_ports)
}
}
diff --git a/components/script/dom/bindings/transferable.rs b/components/script/dom/bindings/transferable.rs
index 7c052e41294..e6b2f000f3a 100644
--- a/components/script/dom/bindings/transferable.rs
+++ b/components/script/dom/bindings/transferable.rs
@@ -6,44 +6,33 @@
//! (<https://html.spec.whatwg.org/multipage/#transferable-objects>).
use std::collections::HashMap;
-use std::num::NonZeroU32;
+use std::hash::Hash;
-use base::id::PipelineNamespaceId;
+use base::id::NamespaceIndex;
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::DomRoot;
-use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader};
+use crate::dom::bindings::structuredclone::StructuredData;
use crate::dom::globalscope::GlobalScope;
-
-pub(crate) trait IdFromComponents
-where
- Self: Sized,
-{
- fn from(namespace_id: PipelineNamespaceId, index: NonZeroU32) -> Self;
-}
-
-pub(crate) trait ExtractComponents {
- fn components(&self) -> (PipelineNamespaceId, NonZeroU32);
-}
-
pub(crate) trait Transferable: DomObject
where
Self: Sized,
{
- type Id: Eq + std::hash::Hash + Copy + IdFromComponents + ExtractComponents;
+ type Index: Copy + Eq + Hash;
type Data;
fn can_transfer(&self) -> bool {
true
}
- fn transfer(&self) -> Result<(Self::Id, Self::Data), ()>;
+ fn transfer(&self) -> Result<(NamespaceIndex<Self::Index>, Self::Data), ()>;
fn transfer_receive(
owner: &GlobalScope,
- id: Self::Id,
+ id: NamespaceIndex<Self::Index>,
serialized: Self::Data,
) -> Result<DomRoot<Self>, ()>;
- fn serialized_storage(data: StructuredData<'_>) -> &mut Option<HashMap<Self::Id, Self::Data>>;
- fn deserialized_storage(reader: &mut StructuredDataReader) -> &mut Option<Vec<DomRoot<Self>>>;
+ fn serialized_storage<'a>(
+ data: StructuredData<'a, '_>,
+ ) -> &'a mut Option<HashMap<NamespaceIndex<Self::Index>, Self::Data>>;
}
diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs
index 5f9d4052929..27aa382c3fc 100644
--- a/components/script/dom/blob.rs
+++ b/components/script/dom/blob.rs
@@ -3,11 +3,10 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::collections::HashMap;
-use std::num::NonZeroU32;
use std::ptr;
use std::rc::Rc;
-use base::id::{BlobId, BlobIndex, PipelineNamespaceId};
+use base::id::{BlobId, BlobIndex};
use constellation_traits::BlobImpl;
use dom_struct::dom_struct;
use encoding_rs::UTF_8;
@@ -25,9 +24,9 @@ use crate::dom::bindings::codegen::UnionTypes::ArrayBufferOrArrayBufferViewOrBlo
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto};
use crate::dom::bindings::root::DomRoot;
-use crate::dom::bindings::serializable::{IntoStorageKey, Serializable, StorageKey};
+use crate::dom::bindings::serializable::Serializable;
use crate::dom::bindings::str::DOMString;
-use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader};
+use crate::dom::bindings::structuredclone::StructuredData;
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use crate::dom::readablestream::ReadableStream;
@@ -94,7 +93,7 @@ impl Blob {
}
impl Serializable for Blob {
- type Id = BlobId;
+ type Index = BlobIndex;
type Data = BlobImpl;
/// <https://w3c.github.io/FileAPI/#ref-for-serialization-steps>
@@ -120,40 +119,14 @@ impl Serializable for Blob {
Ok(deserialized_blob)
}
- fn serialized_storage(
- reader: StructuredData<'_>,
- ) -> &mut Option<HashMap<Self::Id, Self::Data>> {
+ fn serialized_storage<'a>(
+ reader: StructuredData<'a, '_>,
+ ) -> &'a mut Option<HashMap<BlobId, Self::Data>> {
match reader {
StructuredData::Reader(r) => &mut r.blob_impls,
StructuredData::Writer(w) => &mut w.blobs,
}
}
-
- fn deserialized_storage(
- data: &mut StructuredDataReader,
- ) -> &mut Option<HashMap<StorageKey, DomRoot<Self>>> {
- &mut data.blobs
- }
-}
-
-impl From<StorageKey> for BlobId {
- fn from(storage_key: StorageKey) -> BlobId {
- let namespace_id = PipelineNamespaceId(storage_key.name_space);
- let index =
- BlobIndex(NonZeroU32::new(storage_key.index).expect("Deserialized blob index is zero"));
-
- BlobId {
- namespace_id,
- index,
- }
- }
-}
-
-impl IntoStorageKey for BlobId {
- fn into_storage_key(self) -> StorageKey {
- let BlobIndex(index) = self.index;
- StorageKey::new(self.namespace_id, index)
- }
}
/// Extract bytes from BlobParts, used by Blob and File constructor
diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs
index f6bf432de69..73052e6906e 100644
--- a/components/script/dom/canvasrenderingcontext2d.rs
+++ b/components/script/dom/canvasrenderingcontext2d.rs
@@ -5,11 +5,11 @@
use canvas_traits::canvas::{Canvas2dMsg, CanvasId, CanvasMsg, FromScriptMsg};
use dom_struct::dom_struct;
use euclid::default::{Point2D, Rect, Size2D};
-use ipc_channel::ipc::IpcSharedMemory;
use profile_traits::ipc;
use script_bindings::inheritance::Castable;
use script_layout_interface::HTMLCanvasDataSource;
use servo_url::ServoUrl;
+use snapshot::Snapshot;
use crate::canvas_context::{CanvasContext, CanvasHelpers, LayoutCanvasRenderingContextHelpers};
use crate::canvas_state::CanvasState;
@@ -142,16 +142,18 @@ impl CanvasContext for CanvasRenderingContext2D {
self.set_bitmap_dimensions(self.size().cast())
}
- fn get_image_data_as_shared_memory(&self) -> Option<IpcSharedMemory> {
+ fn get_image_data(&self) -> Option<Snapshot> {
+ let size = self.size();
+
+ if size.is_empty() {
+ return None;
+ }
+
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
let msg = CanvasMsg::FromScript(FromScriptMsg::SendPixels(sender), self.get_canvas_id());
self.canvas_state.get_ipc_renderer().send(msg).unwrap();
- Some(receiver.recv().unwrap())
- }
-
- fn get_image_data(&self) -> Option<Vec<u8>> {
- Some(self.get_rect(Rect::from_size(self.size().cast())))
+ Some(receiver.recv().unwrap().to_owned())
}
fn origin_is_clean(&self) -> bool {
diff --git a/components/script/dom/cssstylesheet.rs b/components/script/dom/cssstylesheet.rs
index 421e8f45523..a367c9943de 100644
--- a/components/script/dom/cssstylesheet.rs
+++ b/components/script/dom/cssstylesheet.rs
@@ -24,7 +24,7 @@ use crate::dom::bindings::reflector::{
DomGlobal, reflect_dom_object, reflect_dom_object_with_proto,
};
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
-use crate::dom::bindings::str::DOMString;
+use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::cssrulelist::{CSSRuleList, RulesSource};
use crate::dom::element::Element;
use crate::dom::medialist::MediaList;
@@ -290,4 +290,32 @@ impl CSSStyleSheetMethods<crate::DomTypeHolder> for CSSStyleSheet {
// > 8. Return -1.
Ok(-1)
}
+
+ /// <https://drafts.csswg.org/cssom/#synchronously-replace-the-rules-of-a-cssstylesheet>
+ fn ReplaceSync(&self, text: USVString) -> Result<(), Error> {
+ // Step 1. If the constructed flag is not set throw a NotAllowedError
+ if !self.is_constructed {
+ return Err(Error::NotAllowed);
+ }
+
+ // Step 2. Let rules be the result of running parse a stylesheet’s contents from text.
+ let global = self.global();
+ let window = global.as_window();
+
+ StyleStyleSheet::update_from_str(
+ &self.style_stylesheet,
+ &text,
+ UrlExtraData(window.get_url().get_arc()),
+ None,
+ window.css_error_reporter(),
+ AllowImportRules::No, // Step 3.If rules contains one or more @import rules, remove those rules from rules.
+ );
+
+ // Step 4. Set sheet’s CSS rules to rules.
+ // We reset our rule list, which will be initialized properly
+ // at the next getter access.
+ self.rulelist.set(None);
+
+ Ok(())
+ }
}
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 852a12fc7c5..02bdd343d89 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -21,9 +21,7 @@ use base::id::WebViewId;
use canvas_traits::canvas::CanvasId;
use canvas_traits::webgl::{self, WebGLContextId, WebGLMsg};
use chrono::Local;
-use constellation_traits::{
- AnimationTickType, NavigationHistoryBehavior, ScriptToConstellationMessage,
-};
+use constellation_traits::{NavigationHistoryBehavior, ScriptToConstellationMessage};
use content_security_policy::{self as csp, CspList, PolicyDisposition};
use cookie::Cookie;
use cssparser::match_ignore_ascii_case;
@@ -516,10 +514,6 @@ pub(crate) struct Document {
pending_input_events: DomRefCell<Vec<ConstellationInputEvent>>,
/// The index of the last mouse move event in the pending compositor events queue.
mouse_move_event_index: DomRefCell<Option<usize>>,
- /// Pending animation ticks, to be handled at the next rendering opportunity.
- #[no_trace]
- #[ignore_malloc_size_of = "AnimationTickType contains data from an outside crate"]
- pending_animation_ticks: DomRefCell<AnimationTickType>,
/// <https://drafts.csswg.org/resize-observer/#dom-document-resizeobservers-slot>
///
/// Note: we are storing, but never removing, resize observers.
@@ -2397,10 +2391,6 @@ impl Document {
pub(crate) fn run_the_animation_frame_callbacks(&self, can_gc: CanGc) {
let _realm = enter_realm(self);
- self.pending_animation_ticks
- .borrow_mut()
- .remove(AnimationTickType::REQUEST_ANIMATION_FRAME);
-
self.running_animation_callbacks.set(true);
let was_faking_animation_frames = self.is_faking_animation_frames();
let timing = self.global().performance().Now();
@@ -3916,7 +3906,6 @@ impl Document {
image_animation_manager: DomRefCell::new(ImageAnimationManager::new()),
dirty_root: Default::default(),
declarative_refresh: Default::default(),
- pending_animation_ticks: Default::default(),
pending_input_events: Default::default(),
mouse_move_event_index: Default::default(),
resize_observers: Default::default(),
@@ -4689,18 +4678,6 @@ impl Document {
.collect()
}
- /// Note a pending animation tick, to be processed at the next `update_the_rendering` task.
- pub(crate) fn note_pending_animation_tick(&self, tick_type: AnimationTickType) {
- self.pending_animation_ticks.borrow_mut().extend(tick_type);
- }
-
- /// Whether this document has received an animation tick for rafs.
- pub(crate) fn has_received_raf_tick(&self) -> bool {
- self.pending_animation_ticks
- .borrow()
- .contains(AnimationTickType::REQUEST_ANIMATION_FRAME)
- }
-
pub(crate) fn advance_animation_timeline_for_testing(&self, delta: f64) {
self.animation_timeline.borrow_mut().advance_specific(delta);
let current_timeline_value = self.current_animation_timeline_value();
@@ -6437,10 +6414,7 @@ impl FakeRequestAnimationFrameCallback {
pub(crate) fn invoke(self, can_gc: CanGc) {
// TODO: Once there is a more generic mechanism to trigger `update_the_rendering` when
// not driven by the compositor, it should be used here.
- self.document
- .root()
- .note_pending_animation_tick(AnimationTickType::REQUEST_ANIMATION_FRAME);
- with_script_thread(|script_thread| script_thread.update_the_rendering(false, can_gc))
+ with_script_thread(|script_thread| script_thread.update_the_rendering(true, can_gc))
}
}
diff --git a/components/script/dom/domexception.rs b/components/script/dom/domexception.rs
index 35a21556a2d..fbb807b7a95 100644
--- a/components/script/dom/domexception.rs
+++ b/components/script/dom/domexception.rs
@@ -3,9 +3,8 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::collections::HashMap;
-use std::num::NonZeroU32;
-use base::id::{DomExceptionId, DomExceptionIndex, PipelineNamespaceId};
+use base::id::{DomExceptionId, DomExceptionIndex};
use constellation_traits::DomException;
use dom_struct::dom_struct;
use js::rust::HandleObject;
@@ -18,9 +17,9 @@ use crate::dom::bindings::reflector::{
Reflector, reflect_dom_object, reflect_dom_object_with_proto,
};
use crate::dom::bindings::root::DomRoot;
-use crate::dom::bindings::serializable::{IntoStorageKey, Serializable, StorageKey};
+use crate::dom::bindings::serializable::Serializable;
use crate::dom::bindings::str::DOMString;
-use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader};
+use crate::dom::bindings::structuredclone::StructuredData;
use crate::dom::globalscope::GlobalScope;
use crate::script_runtime::CanGc;
@@ -54,6 +53,7 @@ pub(crate) enum DOMErrorName {
NotReadableError,
DataError,
OperationError,
+ NotAllowedError,
}
impl DOMErrorName {
@@ -85,6 +85,7 @@ impl DOMErrorName {
"NotReadableError" => Some(DOMErrorName::NotReadableError),
"DataError" => Some(DOMErrorName::DataError),
"OperationError" => Some(DOMErrorName::OperationError),
+ "NotAllowedError" => Some(DOMErrorName::NotAllowedError),
_ => None,
}
}
@@ -136,6 +137,10 @@ impl DOMException {
DOMErrorName::OperationError => {
"The operation failed for an operation-specific reason."
},
+ DOMErrorName::NotAllowedError => {
+ r#"The request is not allowed by the user agent or the platform in the current context,
+ possibly because the user denied permission."#
+ },
};
(
@@ -224,11 +229,11 @@ impl DOMExceptionMethods<crate::DomTypeHolder> for DOMException {
}
impl Serializable for DOMException {
- type Id = DomExceptionId;
+ type Index = DomExceptionIndex;
type Data = DomException;
// https://webidl.spec.whatwg.org/#idl-DOMException
- fn serialize(&self) -> Result<(Self::Id, Self::Data), ()> {
+ fn serialize(&self) -> Result<(DomExceptionId, Self::Data), ()> {
let serialized = DomException {
message: self.message.to_string(),
name: self.name.to_string(),
@@ -253,37 +258,12 @@ impl Serializable for DOMException {
))
}
- fn serialized_storage(data: StructuredData<'_>) -> &mut Option<HashMap<Self::Id, Self::Data>> {
+ fn serialized_storage<'a>(
+ data: StructuredData<'a, '_>,
+ ) -> &'a mut Option<HashMap<DomExceptionId, Self::Data>> {
match data {
StructuredData::Reader(reader) => &mut reader.exceptions,
StructuredData::Writer(writer) => &mut writer.exceptions,
}
}
-
- fn deserialized_storage(
- reader: &mut StructuredDataReader,
- ) -> &mut Option<HashMap<StorageKey, DomRoot<Self>>> {
- &mut reader.dom_exceptions
- }
-}
-
-impl From<StorageKey> for DomExceptionId {
- fn from(storage_key: StorageKey) -> DomExceptionId {
- let namespace_id = PipelineNamespaceId(storage_key.name_space);
- let index = DomExceptionIndex(
- NonZeroU32::new(storage_key.index).expect("Deserialized exception index is zero"),
- );
-
- DomExceptionId {
- namespace_id,
- index,
- }
- }
-}
-
-impl IntoStorageKey for DomExceptionId {
- fn into_storage_key(self) -> StorageKey {
- let DomExceptionIndex(index) = self.index;
- StorageKey::new(self.namespace_id, index)
- }
}
diff --git a/components/script/dom/dompoint.rs b/components/script/dom/dompoint.rs
index c6323b28cf7..5e848c43c47 100644
--- a/components/script/dom/dompoint.rs
+++ b/components/script/dom/dompoint.rs
@@ -4,7 +4,7 @@
use std::collections::HashMap;
-use base::id::DomPointId;
+use base::id::{DomPointId, DomPointIndex};
use constellation_traits::DomPoint;
use dom_struct::dom_struct;
use js::rust::HandleObject;
@@ -14,8 +14,8 @@ use crate::dom::bindings::codegen::Bindings::DOMPointReadOnlyBinding::DOMPointRe
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::bindings::serializable::Serializable;
+use crate::dom::bindings::structuredclone::StructuredData;
use crate::dom::dompointreadonly::{DOMPointReadOnly, DOMPointWriteMethods};
use crate::dom::globalscope::GlobalScope;
use crate::script_runtime::CanGc;
@@ -132,10 +132,10 @@ impl DOMPointMethods<crate::DomTypeHolder> for DOMPoint {
}
impl Serializable for DOMPoint {
- type Id = DomPointId;
+ type Index = DomPointIndex;
type Data = DomPoint;
- fn serialize(&self) -> Result<(Self::Id, Self::Data), ()> {
+ fn serialize(&self) -> Result<(DomPointId, Self::Data), ()> {
let serialized = DomPoint {
x: self.X(),
y: self.Y(),
@@ -163,16 +163,12 @@ impl Serializable for DOMPoint {
))
}
- fn serialized_storage(data: StructuredData<'_>) -> &mut Option<HashMap<Self::Id, Self::Data>> {
+ fn serialized_storage<'a>(
+ data: StructuredData<'a, '_>,
+ ) -> &'a mut Option<HashMap<DomPointId, Self::Data>> {
match data {
StructuredData::Reader(reader) => &mut reader.points,
StructuredData::Writer(writer) => &mut writer.points,
}
}
-
- fn deserialized_storage(
- reader: &mut StructuredDataReader,
- ) -> &mut Option<HashMap<StorageKey, DomRoot<Self>>> {
- &mut reader.dom_points
- }
}
diff --git a/components/script/dom/dompointreadonly.rs b/components/script/dom/dompointreadonly.rs
index 0bd6d5742c7..eb6bc9b93a9 100644
--- a/components/script/dom/dompointreadonly.rs
+++ b/components/script/dom/dompointreadonly.rs
@@ -4,9 +4,8 @@
use std::cell::Cell;
use std::collections::HashMap;
-use std::num::NonZeroU32;
-use base::id::{DomPointId, DomPointIndex, PipelineNamespaceId};
+use base::id::{DomPointId, DomPointIndex};
use constellation_traits::DomPoint;
use dom_struct::dom_struct;
use js::rust::HandleObject;
@@ -16,8 +15,8 @@ use crate::dom::bindings::codegen::Bindings::DOMPointReadOnlyBinding::DOMPointRe
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::bindings::serializable::Serializable;
+use crate::dom::bindings::structuredclone::StructuredData;
use crate::dom::globalscope::GlobalScope;
use crate::script_runtime::CanGc;
@@ -142,10 +141,10 @@ impl DOMPointWriteMethods for DOMPointReadOnly {
}
impl Serializable for DOMPointReadOnly {
- type Id = DomPointId;
+ type Index = DomPointIndex;
type Data = DomPoint;
- fn serialize(&self) -> Result<(Self::Id, Self::Data), ()> {
+ fn serialize(&self) -> Result<(DomPointId, Self::Data), ()> {
let serialized = DomPoint {
x: self.x.get(),
y: self.y.get(),
@@ -173,37 +172,12 @@ impl Serializable for DOMPointReadOnly {
))
}
- fn serialized_storage(data: StructuredData<'_>) -> &mut Option<HashMap<Self::Id, Self::Data>> {
+ fn serialized_storage<'a>(
+ data: StructuredData<'a, '_>,
+ ) -> &'a mut Option<HashMap<DomPointId, Self::Data>> {
match data {
StructuredData::Reader(r) => &mut r.points,
StructuredData::Writer(w) => &mut w.points,
}
}
-
- fn deserialized_storage(
- reader: &mut StructuredDataReader,
- ) -> &mut Option<HashMap<StorageKey, DomRoot<Self>>> {
- &mut reader.points_read_only
- }
-}
-
-impl From<StorageKey> 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/globalscope.rs b/components/script/dom/globalscope.rs
index 2658911c795..77d1ee37c03 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -2880,15 +2880,11 @@ impl GlobalScope {
return p;
}
- if let Some((data, size)) = canvas.fetch_all_data() {
- let data = data
- .map(|data| data.to_vec())
- .unwrap_or_else(|| vec![0; size.area() as usize * 4]);
-
+ if let Some(snapshot) = canvas.get_image_data() {
+ let size = snapshot.size().cast();
let image_bitmap =
ImageBitmap::new(self, size.width, size.height, can_gc).unwrap();
-
- image_bitmap.set_bitmap_data(data);
+ image_bitmap.set_bitmap_data(snapshot.to_vec());
image_bitmap.set_origin_clean(canvas.origin_is_clean());
p.resolve_native(&(image_bitmap), can_gc);
}
@@ -2901,14 +2897,11 @@ impl GlobalScope {
return p;
}
- if let Some((data, size)) = canvas.fetch_all_data() {
- let data = data
- .map(|data| data.to_vec())
- .unwrap_or_else(|| vec![0; size.area() as usize * 4]);
-
+ if let Some(snapshot) = canvas.get_image_data() {
+ let size = snapshot.size().cast();
let image_bitmap =
ImageBitmap::new(self, size.width, size.height, can_gc).unwrap();
- image_bitmap.set_bitmap_data(data);
+ image_bitmap.set_bitmap_data(snapshot.to_vec());
image_bitmap.set_origin_clean(canvas.origin_is_clean());
p.resolve_native(&(image_bitmap), can_gc);
}
diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs
index 9e20539ceca..303c781c8b3 100644
--- a/components/script/dom/htmlcanvaselement.rs
+++ b/components/script/dom/htmlcanvaselement.rs
@@ -17,7 +17,6 @@ use image::codecs::jpeg::JpegEncoder;
use image::codecs::png::PngEncoder;
use image::codecs::webp::WebPEncoder;
use image::{ColorType, ImageEncoder};
-use ipc_channel::ipc::IpcSharedMemory;
#[cfg(feature = "webgpu")]
use ipc_channel::ipc::{self as ipcchan};
use js::error::throw_type_error;
@@ -25,6 +24,7 @@ use js::rust::{HandleObject, HandleValue};
use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource};
use servo_media::streams::MediaStreamType;
use servo_media::streams::registry::MediaStreamId;
+use snapshot::Snapshot;
use style::attr::AttrValue;
use crate::canvas_context::CanvasContext as _;
@@ -69,6 +69,7 @@ use crate::script_runtime::{CanGc, JSContext};
const DEFAULT_WIDTH: u32 = 300;
const DEFAULT_HEIGHT: u32 = 150;
+#[derive(PartialEq)]
enum EncodedImageType {
Png,
Jpeg,
@@ -375,42 +376,21 @@ impl HTMLCanvasElement {
self.Height() != 0 && self.Width() != 0
}
- pub(crate) fn fetch_all_data(&self) -> Option<(Option<IpcSharedMemory>, Size2D<u32>)> {
- let size = self.get_size();
-
- if size.width == 0 || size.height == 0 {
- return None;
- }
-
- let data = match self.context.borrow().as_ref() {
- Some(CanvasContext::Context2d(context)) => context.get_image_data_as_shared_memory(),
- Some(CanvasContext::WebGL(_context)) => {
- // TODO: add a method in WebGLRenderingContext to get the pixels.
- return None;
- },
- Some(CanvasContext::WebGL2(_context)) => {
- // TODO: add a method in WebGL2RenderingContext to get the pixels.
- return None;
- },
- #[cfg(feature = "webgpu")]
- Some(CanvasContext::WebGPU(context)) => context.get_image_data_as_shared_memory(),
- Some(CanvasContext::Placeholder(context)) => return context.fetch_all_data(),
- None => None,
- };
-
- Some((data, size))
- }
-
- fn get_content(&self) -> Option<Vec<u8>> {
- match *self.context.borrow() {
- Some(CanvasContext::Context2d(ref context)) => context.get_image_data(),
- Some(CanvasContext::WebGL(ref context)) => context.get_image_data(),
- Some(CanvasContext::WebGL2(ref context)) => context.get_image_data(),
+ 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(ref context)) => context.get_image_data(),
- Some(CanvasContext::Placeholder(_)) | None => {
- // Each pixel is fully-transparent black.
- Some(vec![0; (self.Width() * self.Height() * 4) as usize])
+ Some(CanvasContext::WebGPU(context)) => context.get_image_data(),
+ Some(CanvasContext::Placeholder(context)) => context.get_image_data(),
+ None => {
+ let size = self.get_size();
+ if size.width == 0 || size.height == 0 {
+ None
+ } else {
+ Some(Snapshot::cleared(size.cast()))
+ }
},
}
}
@@ -560,11 +540,23 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
}
// Step 3.
- let Some(file) = self.get_content() else {
+ let Some(mut snapshot) = self.get_image_data() else {
return Ok(USVString("data:,".into()));
};
let image_type = EncodedImageType::from(mime_type);
+ snapshot.transform(
+ if image_type == EncodedImageType::Jpeg {
+ snapshot::AlphaMode::AsOpaque {
+ premultiplied: true,
+ }
+ } else {
+ snapshot::AlphaMode::Transparent {
+ premultiplied: false,
+ }
+ },
+ snapshot::PixelFormat::RGBA,
+ );
let mut url = format!("data:{};base64,", image_type.as_mime_type());
let mut encoder = base64::write::EncoderStringWriter::from_consumer(
@@ -575,7 +567,7 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
self.encode_for_mime_type(
&image_type,
Self::maybe_quality(quality),
- &file,
+ snapshot.data(),
&mut encoder,
);
encoder.into_inner();
@@ -604,7 +596,7 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
let result = if self.Width() == 0 || self.Height() == 0 {
None
} else {
- self.get_content()
+ self.get_image_data()
};
let this = Trusted::new(self);
@@ -625,13 +617,17 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
return error!("Expected blob callback, but found none!");
};
- if let Some(bytes) = result {
+ if let Some(mut snapshot) = result {
+ snapshot.transform(
+ snapshot::AlphaMode::Transparent{ premultiplied: false },
+ snapshot::PixelFormat::RGBA
+ );
// Step 4.1
// If result is non-null, then set result to a serialization of result as a file with
// type and quality if given.
let mut encoded: Vec<u8> = vec![];
- this.encode_for_mime_type(&image_type, quality, &bytes, &mut encoded);
+ this.encode_for_mime_type(&image_type, quality, snapshot.data(), &mut encoded);
let blob_impl = BlobImpl::new_from_bytes(encoded, image_type.as_mime_type());
// Step 4.2.1 & 4.2.2
// Set result to a new Blob object, created in the relevant realm of this canvas element
diff --git a/components/script/dom/messageport.rs b/components/script/dom/messageport.rs
index c3904dbb19a..85d94c1aa7a 100644
--- a/components/script/dom/messageport.rs
+++ b/components/script/dom/messageport.rs
@@ -4,11 +4,10 @@
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
-use std::num::NonZeroU32;
use std::ptr;
use std::rc::Rc;
-use base::id::{MessagePortId, MessagePortIndex, PipelineNamespaceId};
+use base::id::{MessagePortId, MessagePortIndex};
use constellation_traits::{MessagePortImpl, PortMessageTask};
use dom_struct::dom_struct;
use js::jsapi::{Heap, JS_NewObject, JSObject};
@@ -24,9 +23,9 @@ use crate::dom::bindings::error::{Error, ErrorResult, ErrorToJsval};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
use crate::dom::bindings::root::DomRoot;
-use crate::dom::bindings::structuredclone::{self, StructuredData, StructuredDataReader};
+use crate::dom::bindings::structuredclone::{self, StructuredData};
use crate::dom::bindings::trace::RootedTraceableBox;
-use crate::dom::bindings::transferable::{ExtractComponents, IdFromComponents, Transferable};
+use crate::dom::bindings::transferable::Transferable;
use crate::dom::bindings::utils::set_dictionary_property;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
@@ -239,7 +238,7 @@ impl MessagePort {
}
impl Transferable for MessagePort {
- type Id = MessagePortId;
+ type Index = MessagePortIndex;
type Data = MessagePortImpl;
/// <https://html.spec.whatwg.org/multipage/#message-ports:transfer-steps>
@@ -269,31 +268,14 @@ impl Transferable for MessagePort {
Ok(transferred_port)
}
- fn serialized_storage(data: StructuredData<'_>) -> &mut Option<HashMap<Self::Id, Self::Data>> {
+ fn serialized_storage<'a>(
+ data: StructuredData<'a, '_>,
+ ) -> &'a mut Option<HashMap<MessagePortId, Self::Data>> {
match data {
StructuredData::Reader(r) => &mut r.port_impls,
StructuredData::Writer(w) => &mut w.ports,
}
}
-
- fn deserialized_storage(reader: &mut StructuredDataReader) -> &mut Option<Vec<DomRoot<Self>>> {
- &mut reader.message_ports
- }
-}
-
-impl IdFromComponents for MessagePortId {
- fn from(namespace_id: PipelineNamespaceId, index: NonZeroU32) -> MessagePortId {
- MessagePortId {
- namespace_id,
- index: MessagePortIndex(index),
- }
- }
-}
-
-impl ExtractComponents for MessagePortId {
- fn components(&self) -> (PipelineNamespaceId, NonZeroU32) {
- (self.namespace_id, self.index.0)
- }
}
impl MessagePortMethods<crate::DomTypeHolder> for MessagePort {
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 2a01370085a..45a107ae673 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -167,7 +167,6 @@ pub struct Node {
/// Layout data for this node. This is populated during layout and can
/// be used for incremental relayout and script queries.
- #[ignore_malloc_size_of = "trait object"]
#[no_trace]
layout_data: DomRefCell<Option<Box<GenericLayoutData>>>,
}
diff --git a/components/script/dom/offscreencanvas.rs b/components/script/dom/offscreencanvas.rs
index 0587fbad12b..aabe5955e12 100644
--- a/components/script/dom/offscreencanvas.rs
+++ b/components/script/dom/offscreencanvas.rs
@@ -6,8 +6,8 @@ use std::cell::Cell;
use dom_struct::dom_struct;
use euclid::default::Size2D;
-use ipc_channel::ipc::IpcSharedMemory;
use js::rust::{HandleObject, HandleValue};
+use snapshot::Snapshot;
use crate::dom::bindings::cell::{DomRefCell, Ref, ref_filter_map};
use crate::dom::bindings::codegen::Bindings::OffscreenCanvasBinding::{
@@ -88,21 +88,18 @@ impl OffscreenCanvas {
ref_filter_map(self.context.borrow(), |ctx| ctx.as_ref())
}
- pub(crate) fn fetch_all_data(&self) -> Option<(Option<IpcSharedMemory>, Size2D<u32>)> {
- let size = self.get_size();
-
- if size.width == 0 || size.height == 0 {
- return None;
- }
-
- let data = match self.context.borrow().as_ref() {
- Some(OffscreenCanvasContext::OffscreenContext2d(context)) => {
- context.get_image_data_as_shared_memory()
+ pub(crate) fn get_image_data(&self) -> Option<Snapshot> {
+ match self.context.borrow().as_ref() {
+ Some(OffscreenCanvasContext::OffscreenContext2d(context)) => context.get_image_data(),
+ None => {
+ let size = self.get_size();
+ if size.width == 0 || size.height == 0 {
+ None
+ } else {
+ Some(Snapshot::cleared(size))
+ }
},
- None => None,
- };
-
- Some((data, size.to_u32()))
+ }
}
pub(crate) fn get_or_init_2d_context(
diff --git a/components/script/dom/offscreencanvasrenderingcontext2d.rs b/components/script/dom/offscreencanvasrenderingcontext2d.rs
index 69a1d41af2e..2f9b52640e6 100644
--- a/components/script/dom/offscreencanvasrenderingcontext2d.rs
+++ b/components/script/dom/offscreencanvasrenderingcontext2d.rs
@@ -8,7 +8,7 @@ use crate::dom::bindings::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanva
use canvas_traits::canvas::Canvas2dMsg;
use dom_struct::dom_struct;
use euclid::default::Size2D;
-use ipc_channel::ipc::IpcSharedMemory;
+use snapshot::Snapshot;
use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::{
CanvasDirection, CanvasFillRule, CanvasImageSource, CanvasLineCap, CanvasLineJoin,
@@ -76,8 +76,8 @@ impl OffscreenCanvasRenderingContext2D {
self.context.origin_is_clean()
}
- pub(crate) fn get_image_data_as_shared_memory(&self) -> Option<IpcSharedMemory> {
- self.context.get_image_data_as_shared_memory()
+ pub(crate) fn get_image_data(&self) -> Option<Snapshot> {
+ self.context.get_image_data()
}
}
diff --git a/components/script/dom/readablestream.rs b/components/script/dom/readablestream.rs
index 49e740c6d6e..37899f18fec 100644
--- a/components/script/dom/readablestream.rs
+++ b/components/script/dom/readablestream.rs
@@ -8,6 +8,8 @@ use std::ptr::{self};
use std::rc::Rc;
use std::collections::HashMap;
+use base::id::{MessagePortId, MessagePortIndex};
+use constellation_traits::MessagePortImpl;
use dom_struct::dom_struct;
use js::conversions::ToJSValConvertible;
use js::jsapi::{Heap, JSObject};
@@ -56,10 +58,8 @@ use crate::js::conversions::FromJSValConvertible;
use crate::realms::{enter_realm, InRealm};
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
use crate::dom::promisenativehandler::{Callback, PromiseNativeHandler};
-use base::id::MessagePortId;
-use constellation_traits::MessagePortImpl;
use crate::dom::bindings::transferable::Transferable;
-use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader};
+use crate::dom::bindings::structuredclone::StructuredData;
use super::bindings::buffer_source::HeapBufferSource;
use super::bindings::codegen::Bindings::ReadableStreamBYOBReaderBinding::ReadableStreamBYOBReaderReadOptions;
@@ -2179,7 +2179,7 @@ pub(crate) fn get_read_promise_bytes(
/// <https://streams.spec.whatwg.org/#rs-transfer>
impl Transferable for ReadableStream {
- type Id = MessagePortId;
+ type Index = MessagePortIndex;
type Data = MessagePortImpl;
/// <https://streams.spec.whatwg.org/#ref-for-readablestream%E2%91%A1%E2%91%A0>
@@ -2247,14 +2247,12 @@ impl Transferable for ReadableStream {
}
/// Note: we are relying on the port transfer, so the data returned here are related to the port.
- fn serialized_storage(data: StructuredData<'_>) -> &mut Option<HashMap<Self::Id, Self::Data>> {
+ fn serialized_storage<'a>(
+ data: StructuredData<'a, '_>,
+ ) -> &'a mut Option<HashMap<MessagePortId, Self::Data>> {
match data {
StructuredData::Reader(r) => &mut r.port_impls,
StructuredData::Writer(w) => &mut w.ports,
}
}
-
- fn deserialized_storage(reader: &mut StructuredDataReader) -> &mut Option<Vec<DomRoot<Self>>> {
- &mut reader.readable_streams
- }
}
diff --git a/components/script/dom/response.rs b/components/script/dom/response.rs
index 283b7d615aa..cbdfbe94603 100644
--- a/components/script/dom/response.rs
+++ b/components/script/dom/response.rs
@@ -8,7 +8,7 @@ use std::str::FromStr;
use dom_struct::dom_struct;
use http::header::HeaderMap as HyperHeaders;
use hyper_serde::Serde;
-use js::rust::HandleObject;
+use js::rust::{HandleObject, HandleValue};
use net_traits::http_status::HttpStatus;
use servo_url::ServoUrl;
use url::Position;
@@ -24,13 +24,13 @@ use crate::dom::bindings::codegen::Bindings::XMLHttpRequestBinding::BodyInit;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto};
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
-use crate::dom::bindings::str::{ByteString, USVString};
+use crate::dom::bindings::str::{ByteString, USVString, serialize_jsval_to_json_utf8};
use crate::dom::globalscope::GlobalScope;
use crate::dom::headers::{Guard, Headers, is_obs_text, is_vchar};
use crate::dom::promise::Promise;
use crate::dom::readablestream::ReadableStream;
use crate::dom::underlyingsourcecontainer::UnderlyingSourceType;
-use crate::script_runtime::{CanGc, StreamConsumer};
+use crate::script_runtime::{CanGc, JSContext, StreamConsumer};
#[dom_struct]
pub(crate) struct Response {
@@ -72,7 +72,7 @@ impl Response {
}
}
- // https://fetch.spec.whatwg.org/#dom-response
+ /// <https://fetch.spec.whatwg.org/#dom-response>
pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<Response> {
Self::new_with_proto(global, None, can_gc)
}
@@ -142,92 +142,43 @@ fn is_null_body_status(status: u16) -> bool {
}
impl ResponseMethods<crate::DomTypeHolder> for Response {
- // https://fetch.spec.whatwg.org/#initialize-a-response
+ /// <https://fetch.spec.whatwg.org/#dom-response>
fn Constructor(
global: &GlobalScope,
proto: Option<HandleObject>,
can_gc: CanGc,
- body: Option<BodyInit>,
+ body_init: Option<BodyInit>,
init: &ResponseBinding::ResponseInit,
) -> Fallible<DomRoot<Response>> {
- // Step 1
- if init.status < 200 || init.status > 599 {
- return Err(Error::Range(format!(
- "init's status member should be in the range 200 to 599, inclusive, but is {}",
- init.status
- )));
- }
-
- // Step 2
- if !is_valid_status_text(&init.statusText) {
- return Err(Error::Type(
- "init's statusText member does not match the reason-phrase token production"
- .to_string(),
- ));
- }
-
- let r = Response::new_with_proto(global, proto, can_gc);
-
- // Step 3 & 4
- *r.status.borrow_mut() = HttpStatus::new_raw(init.status, init.statusText.clone().into());
-
- // Step 5
- if let Some(ref headers_member) = init.headers {
- r.Headers(can_gc).fill(Some(headers_member.clone()))?;
- }
-
- // Step 6
- if let Some(ref body) = body {
- // Step 6.1
- if is_null_body_status(init.status) {
- return Err(Error::Type(
- "Body is non-null but init's status member is a null body status".to_string(),
- ));
- };
-
- // Step 6.2
- let ExtractedBody {
- stream,
- total_bytes: _,
- content_type,
- source: _,
- } = body.extract(global, can_gc)?;
-
- r.body_stream.set(Some(&*stream));
-
- // Step 6.3
- if let Some(content_type_contents) = content_type {
- if !r
- .Headers(can_gc)
- .Has(ByteString::new(b"Content-Type".to_vec()))
- .unwrap()
- {
- r.Headers(can_gc).Append(
- ByteString::new(b"Content-Type".to_vec()),
- ByteString::new(content_type_contents.as_bytes().to_vec()),
- )?;
- }
- };
- } else {
- // Reset FetchResponse to an in-memory stream with empty byte sequence here for
- // no-init-body case
- let stream = ReadableStream::new_from_bytes(global, Vec::with_capacity(0), can_gc)?;
- r.body_stream.set(Some(&*stream));
- }
+ // 1. Set this’s response to a new response.
+ // Our Response/Body types don't actually hold onto an internal fetch Response.
+ let response = Response::new_with_proto(global, proto, can_gc);
+
+ // 2. Set this’s headers to a new Headers object with this’s relevant realm,
+ // whose header list is this’s response’s header list and guard is "response".
+ response.Headers(can_gc).set_guard(Guard::Response);
+
+ // 3. Let bodyWithType be null.
+ // 4. If body is non-null, then set bodyWithType to the result of extracting body.
+ let body_with_type = match body_init {
+ Some(body) => Some(body.extract(global, can_gc)?),
+ None => None,
+ };
- Ok(r)
+ // 5. Perform *initialize a response* given this, init, and bodyWithType.
+ initialize_response(global, can_gc, body_with_type, init, response)
}
- // https://fetch.spec.whatwg.org/#dom-response-error
+ /// <https://fetch.spec.whatwg.org/#dom-response-error>
fn Error(global: &GlobalScope, can_gc: CanGc) -> DomRoot<Response> {
- let r = Response::new(global, can_gc);
- *r.response_type.borrow_mut() = DOMResponseType::Error;
- r.Headers(can_gc).set_guard(Guard::Immutable);
- *r.status.borrow_mut() = HttpStatus::new_error();
- r
+ let response = Response::new(global, can_gc);
+ *response.response_type.borrow_mut() = DOMResponseType::Error;
+ response.Headers(can_gc).set_guard(Guard::Immutable);
+ *response.status.borrow_mut() = HttpStatus::new_error();
+ response
}
- // https://fetch.spec.whatwg.org/#dom-response-redirect
+ /// <https://fetch.spec.whatwg.org/#dom-response-redirect>
fn Redirect(
global: &GlobalScope,
url: USVString,
@@ -251,31 +202,60 @@ impl ResponseMethods<crate::DomTypeHolder> for Response {
// Step 4
// see Step 4 continued
- let r = Response::new(global, can_gc);
+ let response = Response::new(global, can_gc);
// Step 5
- *r.status.borrow_mut() = HttpStatus::new_raw(status, vec![]);
+ *response.status.borrow_mut() = HttpStatus::new_raw(status, vec![]);
// Step 6
let url_bytestring =
ByteString::from_str(url.as_str()).unwrap_or(ByteString::new(b"".to_vec()));
- r.Headers(can_gc)
+ response
+ .Headers(can_gc)
.Set(ByteString::new(b"Location".to_vec()), url_bytestring)?;
// Step 4 continued
// Headers Guard is set to Immutable here to prevent error in Step 6
- r.Headers(can_gc).set_guard(Guard::Immutable);
+ response.Headers(can_gc).set_guard(Guard::Immutable);
// Step 7
- Ok(r)
+ Ok(response)
+ }
+
+ /// <https://fetch.spec.whatwg.org/#dom-response-json>
+ #[allow(unsafe_code)]
+ fn CreateFromJson(
+ cx: JSContext,
+ global: &GlobalScope,
+ data: HandleValue,
+ init: &ResponseBinding::ResponseInit,
+ can_gc: CanGc,
+ ) -> Fallible<DomRoot<Response>> {
+ // 1. Let bytes the result of running serialize a JavaScript value to JSON bytes on data.
+ let json_str = serialize_jsval_to_json_utf8(cx, data)?;
+
+ // 2. Let body be the result of extracting bytes
+ // The spec's definition of JSON bytes is a UTF-8 encoding so using a DOMString here handles
+ // the encoding part.
+ let body_init = BodyInit::String(json_str);
+ let mut body = body_init.extract(global, can_gc)?;
+
+ // 3. Let responseObject be the result of creating a Response object, given a new response,
+ // "response", and the current realm.
+ let response = Response::new(global, can_gc);
+ response.Headers(can_gc).set_guard(Guard::Response);
+
+ // 4. Perform initialize a response given responseObject, init, and (body, "application/json").
+ body.content_type = Some("application/json".into());
+ initialize_response(global, can_gc, Some(body), init, response)
}
- // https://fetch.spec.whatwg.org/#dom-response-type
+ /// <https://fetch.spec.whatwg.org/#dom-response-type>
fn Type(&self) -> DOMResponseType {
*self.response_type.borrow() //into()
}
- // https://fetch.spec.whatwg.org/#dom-response-url
+ /// <https://fetch.spec.whatwg.org/#dom-response-url>
fn Url(&self) -> USVString {
USVString(String::from(
(*self.url.borrow())
@@ -285,33 +265,33 @@ impl ResponseMethods<crate::DomTypeHolder> for Response {
))
}
- // https://fetch.spec.whatwg.org/#dom-response-redirected
+ /// <https://fetch.spec.whatwg.org/#dom-response-redirected>
fn Redirected(&self) -> bool {
return *self.redirected.borrow();
}
- // https://fetch.spec.whatwg.org/#dom-response-status
+ /// <https://fetch.spec.whatwg.org/#dom-response-status>
fn Status(&self) -> u16 {
self.status.borrow().raw_code()
}
- // https://fetch.spec.whatwg.org/#dom-response-ok
+ /// <https://fetch.spec.whatwg.org/#dom-response-ok>
fn Ok(&self) -> bool {
self.status.borrow().is_success()
}
- // https://fetch.spec.whatwg.org/#dom-response-statustext
+ /// <https://fetch.spec.whatwg.org/#dom-response-statustext>
fn StatusText(&self) -> ByteString {
ByteString::new(self.status.borrow().message().to_vec())
}
- // https://fetch.spec.whatwg.org/#dom-response-headers
+ /// <https://fetch.spec.whatwg.org/#dom-response-headers>
fn Headers(&self, can_gc: CanGc) -> DomRoot<Headers> {
self.headers_reflector
.or_init(|| Headers::for_response(&self.global(), can_gc))
}
- // https://fetch.spec.whatwg.org/#dom-response-clone
+ /// <https://fetch.spec.whatwg.org/#dom-response-clone>
fn Clone(&self, can_gc: CanGc) -> Fallible<DomRoot<Response>> {
// Step 1
if self.is_locked() || self.is_disturbed() {
@@ -352,7 +332,7 @@ impl ResponseMethods<crate::DomTypeHolder> for Response {
Ok(new_response)
}
- // https://fetch.spec.whatwg.org/#dom-body-bodyused
+ /// <https://fetch.spec.whatwg.org/#dom-body-bodyused>
fn BodyUsed(&self) -> bool {
self.is_disturbed()
}
@@ -362,27 +342,27 @@ impl ResponseMethods<crate::DomTypeHolder> for Response {
self.body()
}
- // https://fetch.spec.whatwg.org/#dom-body-text
+ /// <https://fetch.spec.whatwg.org/#dom-body-text>
fn Text(&self, can_gc: CanGc) -> Rc<Promise> {
consume_body(self, BodyType::Text, can_gc)
}
- // https://fetch.spec.whatwg.org/#dom-body-blob
+ /// <https://fetch.spec.whatwg.org/#dom-body-blob>
fn Blob(&self, can_gc: CanGc) -> Rc<Promise> {
consume_body(self, BodyType::Blob, can_gc)
}
- // https://fetch.spec.whatwg.org/#dom-body-formdata
+ /// <https://fetch.spec.whatwg.org/#dom-body-formdata>
fn FormData(&self, can_gc: CanGc) -> Rc<Promise> {
consume_body(self, BodyType::FormData, can_gc)
}
- // https://fetch.spec.whatwg.org/#dom-body-json
+ /// <https://fetch.spec.whatwg.org/#dom-body-json>
fn Json(&self, can_gc: CanGc) -> Rc<Promise> {
consume_body(self, BodyType::Json, can_gc)
}
- // https://fetch.spec.whatwg.org/#dom-body-arraybuffer
+ /// <https://fetch.spec.whatwg.org/#dom-body-arraybuffer>
fn ArrayBuffer(&self, can_gc: CanGc) -> Rc<Promise> {
consume_body(self, BodyType::ArrayBuffer, can_gc)
}
@@ -393,6 +373,80 @@ impl ResponseMethods<crate::DomTypeHolder> for Response {
}
}
+/// <https://fetch.spec.whatwg.org/#initialize-a-response>
+fn initialize_response(
+ global: &GlobalScope,
+ can_gc: CanGc,
+ body: Option<ExtractedBody>,
+ init: &ResponseBinding::ResponseInit,
+ response: DomRoot<Response>,
+) -> Result<DomRoot<Response>, Error> {
+ // 1. If init["status"] is not in the range 200 to 599, inclusive, then throw a RangeError.
+ if init.status < 200 || init.status > 599 {
+ return Err(Error::Range(format!(
+ "init's status member should be in the range 200 to 599, inclusive, but is {}",
+ init.status
+ )));
+ }
+
+ // 2. If init["statusText"] is not the empty string and does not match the reason-phrase token production,
+ // then throw a TypeError.
+ if !is_valid_status_text(&init.statusText) {
+ return Err(Error::Type(
+ "init's statusText member does not match the reason-phrase token production"
+ .to_string(),
+ ));
+ }
+
+ // 3. Set response’s response’s status to init["status"].
+ // 4. Set response’s response’s status message to init["statusText"].
+ *response.status.borrow_mut() =
+ HttpStatus::new_raw(init.status, init.statusText.clone().into());
+
+ // 5. If init["headers"] exists, then fill response’s headers with init["headers"].
+ if let Some(ref headers_member) = init.headers {
+ response
+ .Headers(can_gc)
+ .fill(Some(headers_member.clone()))?;
+ }
+
+ // 6. If body is non-null, then:
+ if let Some(ref body) = body {
+ // 6.1 If response’s status is a null body status, then throw a TypeError.
+ if is_null_body_status(init.status) {
+ return Err(Error::Type(
+ "Body is non-null but init's status member is a null body status".to_string(),
+ ));
+ };
+
+ // 6.2 Set response’s body to body’s body.
+ response.body_stream.set(Some(&*body.stream));
+
+ // 6.3 If body’s type is non-null and response’s header list does not contain `Content-Type`,
+ // then append (`Content-Type`, body’s type) to response’s header list.
+ if let Some(content_type_contents) = &body.content_type {
+ if !response
+ .Headers(can_gc)
+ .Has(ByteString::new(b"Content-Type".to_vec()))
+ .unwrap()
+ {
+ response.Headers(can_gc).Append(
+ ByteString::new(b"Content-Type".to_vec()),
+ ByteString::new(content_type_contents.as_bytes().to_vec()),
+ )?;
+ }
+ };
+ } else {
+ // Reset FetchResponse to an in-memory stream with empty byte sequence here for
+ // no-init-body case. This is because the Response/Body types here do not hold onto a
+ // fetch Response object.
+ let stream = ReadableStream::new_from_bytes(global, Vec::with_capacity(0), can_gc)?;
+ response.body_stream.set(Some(&*stream));
+ }
+
+ Ok(response)
+}
+
fn serialize_without_fragment(url: &ServoUrl) -> &str {
&url[..Position::AfterQuery]
}
diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs
index bb6ffa11849..416454d8719 100644
--- a/components/script/dom/webgl2renderingcontext.rs
+++ b/components/script/dom/webgl2renderingcontext.rs
@@ -24,6 +24,7 @@ use js::typedarray::{ArrayBufferView, CreateWith, Float32, Int32Array, Uint32, U
use script_bindings::interfaces::WebGL2RenderingContextHelpers;
use script_layout_interface::HTMLCanvasDataSource;
use servo_config::pref;
+use snapshot::Snapshot;
use url::Host;
use crate::canvas_context::CanvasContext;
@@ -549,11 +550,11 @@ impl WebGL2RenderingContext {
return
);
- let (sender, receiver) = ipc::bytes_channel().unwrap();
+ let (sender, receiver) = ipc::channel().unwrap();
self.base.send_command(WebGLCommand::ReadPixels(
src_rect, format, pixel_type, sender,
));
- let src = receiver.recv().unwrap();
+ let (src, _) = receiver.recv().unwrap();
for i in 0..src_rect.size.height as usize {
let src_start = i * src_row_bytes as usize;
@@ -916,11 +917,7 @@ impl CanvasContext for WebGL2RenderingContext {
self.base.resize();
}
- fn get_image_data_as_shared_memory(&self) -> Option<IpcSharedMemory> {
- self.base.get_image_data_as_shared_memory()
- }
-
- fn get_image_data(&self) -> Option<Vec<u8>> {
+ fn get_image_data(&self) -> Option<Snapshot> {
self.base.get_image_data()
}
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 1e51ac4baf9..9996a3cf504 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -34,6 +34,7 @@ use pixels::{self, PixelFormat};
use script_layout_interface::HTMLCanvasDataSource;
use serde::{Deserialize, Serialize};
use servo_config::pref;
+use snapshot::Snapshot;
use webrender_api::ImageKey;
use crate::canvas_context::CanvasContext;
@@ -628,11 +629,15 @@ impl WebGLRenderingContext {
if !canvas.origin_is_clean() {
return Err(Error::Security);
}
- if let Some((data, size)) = canvas.fetch_all_data() {
- let data = data.unwrap_or_else(|| {
- IpcSharedMemory::from_bytes(&vec![0; size.area() as usize * 4])
- });
- TexPixels::new(data, size, PixelFormat::BGRA8, true)
+ if let Some(snapshot) = canvas.get_image_data() {
+ let snapshot = snapshot.as_ipc();
+ let size = snapshot.size().cast();
+ let format = match snapshot.format() {
+ snapshot::PixelFormat::RGBA => PixelFormat::RGBA8,
+ snapshot::PixelFormat::BGRA => PixelFormat::BGRA8,
+ };
+ let premultiply = snapshot.alpha_mode().is_premultiplied();
+ TexPixels::new(snapshot.to_ipc_shared_memory(), size, format, premultiply)
} else {
return Ok(None);
}
@@ -1922,18 +1927,13 @@ impl CanvasContext for WebGLRenderingContext {
}
}
- fn get_image_data_as_shared_memory(&self) -> Option<IpcSharedMemory> {
- // TODO: add a method in WebGLRenderingContext to get the pixels.
- None
- }
-
// Used by HTMLCanvasElement.toDataURL
//
// This emits errors quite liberally, but the spec says that this operation
// can fail and that it is UB what happens in that case.
//
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#2.2
- fn get_image_data(&self) -> Option<Vec<u8>> {
+ fn get_image_data(&self) -> Option<Snapshot> {
handle_potential_webgl_error!(self, self.validate_framebuffer(), return None);
let mut size = self.size().cast();
@@ -1945,14 +1945,20 @@ impl CanvasContext for WebGLRenderingContext {
size.width = cmp::min(size.width, fb_width as u32);
size.height = cmp::min(size.height, fb_height as u32);
- let (sender, receiver) = ipc::bytes_channel().unwrap();
+ let (sender, receiver) = ipc::channel().unwrap();
self.send_command(WebGLCommand::ReadPixels(
Rect::from_size(size),
constants::RGBA,
constants::UNSIGNED_BYTE,
sender,
));
- Some(receiver.recv().unwrap())
+ let (data, alpha_mode) = receiver.recv().unwrap();
+ Some(Snapshot::from_vec(
+ size.cast(),
+ snapshot::PixelFormat::RGBA,
+ alpha_mode,
+ data.to_vec(),
+ ))
}
fn mark_as_dirty(&self) {
@@ -3826,11 +3832,11 @@ impl WebGLRenderingContextMethods<crate::DomTypeHolder> for WebGLRenderingContex
dest_offset += -y * row_len;
}
- let (sender, receiver) = ipc::bytes_channel().unwrap();
+ let (sender, receiver) = ipc::channel().unwrap();
self.send_command(WebGLCommand::ReadPixels(
src_rect, format, pixel_type, sender,
));
- let src = receiver.recv().unwrap();
+ let (src, _) = receiver.recv().unwrap();
let src_row_len = src_rect.size.width as usize * bytes_per_pixel as usize;
for i in 0..src_rect.size.height {
diff --git a/components/script/dom/webgpu/gpucanvascontext.rs b/components/script/dom/webgpu/gpucanvascontext.rs
index 595b54c58d7..c81f96f651f 100644
--- a/components/script/dom/webgpu/gpucanvascontext.rs
+++ b/components/script/dom/webgpu/gpucanvascontext.rs
@@ -7,8 +7,9 @@ use std::cell::RefCell;
use arrayvec::ArrayVec;
use dom_struct::dom_struct;
-use ipc_channel::ipc::{self, IpcSharedMemory};
+use ipc_channel::ipc::{self};
use script_layout_interface::HTMLCanvasDataSource;
+use snapshot::Snapshot;
use webgpu_traits::{
ContextConfiguration, PRESENTATION_BUFFER_COUNT, WebGPU, WebGPUContextId, WebGPURequest,
WebGPUTexture,
@@ -277,10 +278,10 @@ impl CanvasContext for GPUCanvasContext {
}
/// <https://gpuweb.github.io/gpuweb/#ref-for-abstract-opdef-get-a-copy-of-the-image-contents-of-a-context%E2%91%A5>
- fn get_image_data_as_shared_memory(&self) -> Option<IpcSharedMemory> {
+ fn get_image_data(&self) -> Option<Snapshot> {
// 1. Return a copy of the image contents of context.
Some(if self.drawing_buffer.borrow().cleared {
- IpcSharedMemory::from_byte(0, self.size().area() as usize * 4)
+ Snapshot::cleared(self.size())
} else {
let (sender, receiver) = ipc::channel().unwrap();
self.channel
@@ -290,7 +291,7 @@ impl CanvasContext for GPUCanvasContext {
sender,
})
.unwrap();
- receiver.recv().unwrap()
+ receiver.recv().unwrap().to_owned()
})
}
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 0308e207e65..9053f7f7e86 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -83,8 +83,8 @@ use style::stylesheets::UrlExtraData;
use style_traits::CSSPixel;
use stylo_atoms::Atom;
use url::Position;
+use webrender_api::ExternalScrollId;
use webrender_api::units::{DevicePixel, LayoutPixel};
-use webrender_api::{DocumentId, ExternalScrollId};
use super::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeOptions;
use super::bindings::trace::HashMapTracedValues;
@@ -353,10 +353,6 @@ pub(crate) struct Window {
test_worklet: MutNullableDom<Worklet>,
/// <https://drafts.css-houdini.org/css-paint-api-1/#paint-worklet>
paint_worklet: MutNullableDom<Worklet>,
- /// The Webrender Document id associated with this window.
- #[ignore_malloc_size_of = "defined in webrender_api"]
- #[no_trace]
- webrender_document: DocumentId,
/// Flag to identify whether mutation observers are present(true)/absent(false)
exists_mut_observer: Cell<bool>,
@@ -1220,15 +1216,26 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
}
}
- #[allow(unsafe_code)]
- fn WebdriverCallback(&self, cx: JSContext, val: HandleValue) {
- let rv = unsafe { jsval_to_webdriver(*cx, &self.globalscope, val) };
+ fn WebdriverCallback(&self, cx: JSContext, val: HandleValue, realm: InRealm, can_gc: CanGc) {
+ let rv = jsval_to_webdriver(cx, &self.globalscope, val, realm, can_gc);
let opt_chan = self.webdriver_script_chan.borrow_mut().take();
if let Some(chan) = opt_chan {
chan.send(rv).unwrap();
}
}
+ fn WebdriverException(&self, cx: JSContext, val: HandleValue, realm: InRealm, can_gc: CanGc) {
+ let rv = jsval_to_webdriver(cx, &self.globalscope, val, realm, can_gc);
+ let opt_chan = self.webdriver_script_chan.borrow_mut().take();
+ if let Some(chan) = opt_chan {
+ if let Ok(rv) = rv {
+ chan.send(Err(WebDriverJSError::JSException(rv))).unwrap();
+ } else {
+ chan.send(rv).unwrap();
+ }
+ }
+ }
+
fn WebdriverTimeout(&self) {
let opt_chan = self.webdriver_script_chan.borrow_mut().take();
if let Some(chan) = opt_chan {
@@ -2285,11 +2292,12 @@ impl Window {
node: Option<&Node>,
can_gc: CanGc,
) -> UntypedRect<i32> {
- let opaque = node.map(|node| node.to_opaque());
if !self.layout_reflow(QueryMsg::ScrollingAreaQuery, can_gc) {
return Rect::zero();
}
- self.layout.borrow().query_scrolling_area(opaque)
+ self.layout
+ .borrow()
+ .query_scrolling_area(node.map(Node::to_trusted_node_address))
}
pub(crate) fn scroll_offset_query(&self, node: &Node) -> Vector2D<f32, LayoutPixel> {
@@ -2775,10 +2783,6 @@ impl Window {
.unwrap();
}
- pub(crate) fn webrender_document(&self) -> DocumentId {
- self.webrender_document
- }
-
#[cfg(feature = "webxr")]
pub(crate) fn in_immersive_xr_session(&self) -> bool {
self.navigator
@@ -2821,7 +2825,6 @@ impl Window {
webgl_chan: Option<WebGLChan>,
#[cfg(feature = "webxr")] webxr_registry: Option<webxr_api::Registry>,
microtask_queue: Rc<MicrotaskQueue>,
- webrender_document: DocumentId,
compositor_api: CrossProcessCompositorApi,
relayout_event: bool,
unminify_js: bool,
@@ -2906,7 +2909,6 @@ impl Window {
local_script_source,
test_worklet: Default::default(),
paint_worklet: Default::default(),
- webrender_document,
exists_mut_observer: Cell::new(false),
compositor_api,
has_sent_idle_message: Cell::new(false),
diff --git a/components/script/dom/writablestream.rs b/components/script/dom/writablestream.rs
index da0fe3b5957..e7e9ce906a6 100644
--- a/components/script/dom/writablestream.rs
+++ b/components/script/dom/writablestream.rs
@@ -8,7 +8,7 @@ use std::mem;
use std::ptr::{self};
use std::rc::Rc;
-use base::id::MessagePortId;
+use base::id::{MessagePortId, MessagePortIndex};
use constellation_traits::MessagePortImpl;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject};
@@ -27,7 +27,7 @@ use crate::dom::bindings::conversions::ConversionResult;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto};
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
-use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader};
+use crate::dom::bindings::structuredclone::StructuredData;
use crate::dom::bindings::transferable::Transferable;
use crate::dom::countqueuingstrategy::{extract_high_water_mark, extract_size_algorithm};
use crate::dom::domexception::{DOMErrorName, DOMException};
@@ -1114,7 +1114,7 @@ impl CrossRealmTransformWritable {
/// <https://streams.spec.whatwg.org/#ws-transfer>
impl Transferable for WritableStream {
- type Id = MessagePortId;
+ type Index = MessagePortIndex;
type Data = MessagePortImpl;
/// <https://streams.spec.whatwg.org/#ref-for-writablestream%E2%91%A0%E2%91%A4>
@@ -1182,14 +1182,12 @@ impl Transferable for WritableStream {
}
/// Note: we are relying on the port transfer, so the data returned here are related to the port.
- fn serialized_storage(data: StructuredData<'_>) -> &mut Option<HashMap<Self::Id, Self::Data>> {
+ fn serialized_storage<'a>(
+ data: StructuredData<'a, '_>,
+ ) -> &'a mut Option<HashMap<MessagePortId, Self::Data>> {
match data {
StructuredData::Reader(r) => &mut r.port_impls,
StructuredData::Writer(w) => &mut w.ports,
}
}
-
- fn deserialized_storage(reader: &mut StructuredDataReader) -> &mut Option<Vec<DomRoot<Self>>> {
- &mut reader.writable_streams
- }
}
diff --git a/components/script/dom/writablestreamdefaultcontroller.rs b/components/script/dom/writablestreamdefaultcontroller.rs
index 4e6a44b9f5a..751f5d8d976 100644
--- a/components/script/dom/writablestreamdefaultcontroller.rs
+++ b/components/script/dom/writablestreamdefaultcontroller.rs
@@ -555,7 +555,7 @@ impl WritableStreamDefaultController {
promise.reject_error(error, can_gc);
} else {
// Otherwise, return a promise resolved with undefined.
- promise.reject_native(&(), can_gc);
+ promise.resolve_native(&(), can_gc);
}
promise
},