diff options
Diffstat (limited to 'components/script/dom')
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 }, |