diff options
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/attr.rs | 10 | ||||
-rw-r--r-- | components/script/dom/bindings/structuredclone.rs | 7 | ||||
-rw-r--r-- | components/script/dom/create.rs | 2 | ||||
-rw-r--r-- | components/script/dom/element.rs | 129 | ||||
-rw-r--r-- | components/script/dom/globalscope.rs | 4 | ||||
-rw-r--r-- | components/script/dom/mod.rs | 1 | ||||
-rw-r--r-- | components/script/dom/node.rs | 3 | ||||
-rw-r--r-- | components/script/dom/promise.rs | 17 | ||||
-rw-r--r-- | components/script/dom/readablestream.rs | 7 | ||||
-rw-r--r-- | components/script/dom/svgelement.rs | 3 | ||||
-rw-r--r-- | components/script/dom/svgimageelement.rs | 96 | ||||
-rw-r--r-- | components/script/dom/transformstream.rs | 106 | ||||
-rw-r--r-- | components/script/dom/trustedhtml.rs | 18 | ||||
-rw-r--r-- | components/script/dom/virtualmethods.rs | 4 |
14 files changed, 354 insertions, 53 deletions
diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs index 52d0ca7e20c..9f1520bd085 100644 --- a/components/script/dom/attr.rs +++ b/components/script/dom/attr.rs @@ -8,7 +8,7 @@ use std::mem; use devtools_traits::AttrInfo; use dom_struct::dom_struct; -use html5ever::{LocalName, Namespace, Prefix, ns}; +use html5ever::{LocalName, Namespace, Prefix, local_name, ns}; use style::attr::{AttrIdentifier, AttrValue}; use style::values::GenericAtomIdent; use stylo_atoms::Atom; @@ -179,7 +179,7 @@ impl Attr { assert_eq!(Some(owner), self.owner().as_deref()); owner.will_mutate_attr(self); self.swap_value(&mut value); - if *self.namespace() == ns!() { + if is_relevant_attribute(self.namespace(), self.local_name()) { vtable_for(owner.upcast()).attribute_mutated( self, AttributeMutation::Set(Some(&value)), @@ -283,3 +283,9 @@ impl<'dom> AttrHelpersForLayout<'dom> for LayoutDom<'dom, Attr> { &self.unsafe_get().identifier.namespace.0 } } + +/// A helper function to check if attribute is relevant. +pub(crate) fn is_relevant_attribute(namespace: &Namespace, local_name: &LocalName) -> bool { + // <https://svgwg.org/svg2-draft/linking.html#XLinkHrefAttribute> + namespace == &ns!() || (namespace == &ns!(xlink) && local_name == &local_name!("href")) +} diff --git a/components/script/dom/bindings/structuredclone.rs b/components/script/dom/bindings/structuredclone.rs index c9a49ba00c9..70638238123 100644 --- a/components/script/dom/bindings/structuredclone.rs +++ b/components/script/dom/bindings/structuredclone.rs @@ -44,7 +44,7 @@ use crate::dom::dompointreadonly::DOMPointReadOnly; use crate::dom::globalscope::GlobalScope; use crate::dom::messageport::MessagePort; use crate::dom::readablestream::ReadableStream; -use crate::dom::types::DOMException; +use crate::dom::types::{DOMException, TransformStream}; use crate::dom::writablestream::WritableStream; use crate::realms::{AlreadyInRealm, InRealm, enter_realm}; use crate::script_runtime::{CanGc, JSContext as SafeJSContext}; @@ -65,6 +65,7 @@ pub(super) enum StructuredCloneTags { ReadableStream = 0xFFFF8006, DomException = 0xFFFF8007, WritableStream = 0xFFFF8008, + TransformStream = 0xFFFF8009, Max = 0xFFFFFFFF, } @@ -85,6 +86,7 @@ impl From<TransferrableInterface> for StructuredCloneTags { TransferrableInterface::MessagePort => StructuredCloneTags::MessagePort, TransferrableInterface::ReadableStream => StructuredCloneTags::ReadableStream, TransferrableInterface::WritableStream => StructuredCloneTags::WritableStream, + TransferrableInterface::TransformStream => StructuredCloneTags::TransformStream, } } } @@ -265,6 +267,7 @@ fn receiver_for_type( TransferrableInterface::MessagePort => receive_object::<MessagePort>, TransferrableInterface::ReadableStream => receive_object::<ReadableStream>, TransferrableInterface::WritableStream => receive_object::<WritableStream>, + TransferrableInterface::TransformStream => receive_object::<TransformStream>, } } @@ -390,6 +393,7 @@ fn transfer_for_type(val: TransferrableInterface) -> TransferOperation { TransferrableInterface::MessagePort => try_transfer::<MessagePort>, TransferrableInterface::ReadableStream => try_transfer::<ReadableStream>, TransferrableInterface::WritableStream => try_transfer::<WritableStream>, + TransferrableInterface::TransformStream => try_transfer::<TransformStream>, } } @@ -438,6 +442,7 @@ unsafe fn can_transfer_for_type( TransferrableInterface::MessagePort => can_transfer::<MessagePort>(obj, cx), TransferrableInterface::ReadableStream => can_transfer::<ReadableStream>(obj, cx), TransferrableInterface::WritableStream => can_transfer::<WritableStream>(obj, cx), + TransferrableInterface::TransformStream => can_transfer::<TransformStream>(obj, cx), } } diff --git a/components/script/dom/create.rs b/components/script/dom/create.rs index 5722dc4f6ac..2e7c4cf8def 100644 --- a/components/script/dom/create.rs +++ b/components/script/dom/create.rs @@ -85,6 +85,7 @@ use crate::dom::htmlulistelement::HTMLUListElement; use crate::dom::htmlunknownelement::HTMLUnknownElement; use crate::dom::htmlvideoelement::HTMLVideoElement; use crate::dom::svgelement::SVGElement; +use crate::dom::svgimageelement::SVGImageElement; use crate::dom::svgsvgelement::SVGSVGElement; use crate::realms::{InRealm, enter_realm}; use crate::script_runtime::CanGc; @@ -114,6 +115,7 @@ fn create_svg_element( } match name.local { + local_name!("image") => make!(SVGImageElement), local_name!("svg") => make!(SVGSVGElement), _ => make!(SVGElement), } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 5c79dbc0a5b..a73c5347d70 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -63,8 +63,9 @@ use xml5ever::serialize::TraversalScope::{ ChildrenOnly as XmlChildrenOnly, IncludeNode as XmlIncludeNode, }; +use crate::conversions::Convert; use crate::dom::activation::Activatable; -use crate::dom::attr::{Attr, AttrHelpersForLayout}; +use crate::dom::attr::{Attr, AttrHelpersForLayout, is_relevant_attribute}; use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut, ref_filter_map}; use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; @@ -80,7 +81,9 @@ use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{ use crate::dom::bindings::codegen::Bindings::WindowBinding::{ ScrollBehavior, ScrollToOptions, WindowMethods, }; -use crate::dom::bindings::codegen::UnionTypes::{NodeOrString, TrustedScriptURLOrUSVString}; +use crate::dom::bindings::codegen::UnionTypes::{ + NodeOrString, TrustedHTMLOrNullIsEmptyString, TrustedHTMLOrString, TrustedScriptURLOrUSVString, +}; use crate::dom::bindings::conversions::DerivedFrom; use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId}; @@ -152,6 +155,7 @@ use crate::dom::raredata::ElementRareData; use crate::dom::servoparser::ServoParser; use crate::dom::shadowroot::{IsUserAgentWidget, ShadowRoot}; use crate::dom::text::Text; +use crate::dom::trustedhtml::TrustedHTML; use crate::dom::validation::Validatable; use crate::dom::validitystate::ValidationFlags; use crate::dom::virtualmethods::{VirtualMethods, vtable_for}; @@ -355,7 +359,7 @@ impl Element { if damage == NodeDamage::OtherNodeDamage { doc.note_node_with_dirty_descendants(self.upcast()); - restyle.damage = RestyleDamage::rebuild_and_reflow(); + restyle.damage = RestyleDamage::reconstruct(); } } @@ -1701,7 +1705,7 @@ impl Element { assert!(attr.GetOwnerElement().as_deref() == Some(self)); self.will_mutate_attr(attr); self.attrs.borrow_mut().push(Dom::from_ref(attr)); - if attr.namespace() == &ns!() { + if is_relevant_attribute(attr.namespace(), attr.local_name()) { vtable_for(self.upcast()).attribute_mutated(attr, AttributeMutation::Set(None), can_gc); } } @@ -1843,7 +1847,7 @@ impl Element { local_name: &LocalName, value: DOMString, ) -> AttrValue { - if *namespace == ns!() { + if is_relevant_attribute(namespace, local_name) { vtable_for(self.upcast()).parse_plain_attribute(local_name, value) } else { AttrValue::String(value.into()) @@ -1898,7 +1902,7 @@ impl Element { self.attrs.borrow_mut().remove(idx); attr.set_owner(None); - if attr.namespace() == &ns!() { + if is_relevant_attribute(attr.namespace(), attr.local_name()) { vtable_for(self.upcast()).attribute_mutated( &attr, AttributeMutation::Removed, @@ -2322,18 +2326,25 @@ impl Element { Ok(fragment) } + /// Step 4 of <https://html.spec.whatwg.org/multipage/#dom-element-insertadjacenthtml> pub(crate) fn fragment_parsing_context( owner_doc: &Document, element: Option<&Self>, can_gc: CanGc, ) -> DomRoot<Self> { + // If context is not an Element or all of the following are true: match element { Some(elem) + // context's node document is an HTML document; + // context's local name is "html"; and + // context's namespace is the HTML namespace, if elem.local_name() != &local_name!("html") || !elem.html_element_in_html_document() => { DomRoot::from_ref(elem) }, + // set context to the result of creating an element + // given this's node document, "body", and the HTML namespace. _ => DomRoot::upcast(HTMLBodyElement::new( local_name!("body"), None, @@ -2446,6 +2457,13 @@ impl Element { Dom::from_ref(&*ElementInternals::new(elem, can_gc)) })) } + + pub(crate) fn outer_html(&self, can_gc: CanGc) -> Fallible<DOMString> { + match self.GetOuterHTML(can_gc)? { + TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(str) => Ok(str), + TrustedHTMLOrNullIsEmptyString::TrustedHTML(_) => unreachable!(), + } + } } impl ElementMethods<crate::DomTypeHolder> for Element { @@ -2704,7 +2722,7 @@ impl ElementMethods<crate::DomTypeHolder> for Element { attr.set_owner(Some(self)); self.attrs.borrow_mut()[position] = Dom::from_ref(attr); old_attr.set_owner(None); - if attr.namespace() == &ns!() { + if is_relevant_attribute(attr.namespace(), attr.local_name()) { vtable.attribute_mutated( attr, AttributeMutation::Set(Some(&old_attr.value())), @@ -3100,7 +3118,17 @@ impl ElementMethods<crate::DomTypeHolder> for Element { } /// <https://html.spec.whatwg.org/multipage/#dom-element-sethtmlunsafe> - fn SetHTMLUnsafe(&self, html: DOMString, can_gc: CanGc) { + fn SetHTMLUnsafe(&self, html: TrustedHTMLOrString, can_gc: CanGc) -> ErrorResult { + // Step 1. Let compliantHTML be the result of invoking the + // Get Trusted Type compliant string algorithm with TrustedHTML, + // this's relevant global object, html, "Element setHTMLUnsafe", and "script". + let html = DOMString::from(TrustedHTML::get_trusted_script_compliant_string( + &self.owner_global(), + html, + "Element", + "setHTMLUnsafe", + can_gc, + )?); // Step 2. Let target be this's template contents if this is a template element; otherwise this. let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() { DomRoot::upcast(template.Content(can_gc)) @@ -3110,6 +3138,7 @@ impl ElementMethods<crate::DomTypeHolder> for Element { // Step 3. Unsafely set HTML given target, this, and compliantHTML Node::unsafely_set_html(&target, self, html, can_gc); + Ok(()) } /// <https://html.spec.whatwg.org/multipage/#dom-element-gethtml> @@ -3125,7 +3154,7 @@ impl ElementMethods<crate::DomTypeHolder> for Element { } /// <https://html.spec.whatwg.org/multipage/#dom-element-innerhtml> - fn GetInnerHTML(&self, can_gc: CanGc) -> Fallible<DOMString> { + fn GetInnerHTML(&self, can_gc: CanGc) -> Fallible<TrustedHTMLOrNullIsEmptyString> { let qname = QualName::new( self.prefix().clone(), self.namespace().clone(), @@ -3142,16 +3171,28 @@ impl ElementMethods<crate::DomTypeHolder> for Element { .xml_serialize(XmlChildrenOnly(Some(qname))) }; - Ok(result) + Ok(TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(result)) } /// <https://html.spec.whatwg.org/multipage/#dom-element-innerhtml> - fn SetInnerHTML(&self, value: DOMString, can_gc: CanGc) -> ErrorResult { - // Step 2. + fn SetInnerHTML(&self, value: TrustedHTMLOrNullIsEmptyString, can_gc: CanGc) -> ErrorResult { + // Step 1: Let compliantString be the result of invoking the + // Get Trusted Type compliant string algorithm with TrustedHTML, + // this's relevant global object, the given value, "Element innerHTML", and "script". + let value = DOMString::from(TrustedHTML::get_trusted_script_compliant_string( + &self.owner_global(), + value.convert(), + "Element", + "innerHTML", + can_gc, + )?); // https://github.com/w3c/DOM-Parsing/issues/1 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() { + // Step 4: If context is a template element, then set context to + // the template element's template contents (a DocumentFragment). DomRoot::upcast(template.Content(can_gc)) } else { + // Step 2: Let context be this. DomRoot::from_ref(self.upcast()) }; @@ -3168,15 +3209,17 @@ impl ElementMethods<crate::DomTypeHolder> for Element { return Ok(()); } - // Step 1. + // Step 3: Let fragment be the result of invoking the fragment parsing algorithm steps + // with context and compliantString. let frag = self.parse_fragment(value, can_gc)?; + // Step 5: Replace all with fragment within context. Node::replace_all(Some(frag.upcast()), &target, can_gc); Ok(()) } /// <https://html.spec.whatwg.org/multipage/#dom-element-outerhtml> - fn GetOuterHTML(&self, can_gc: CanGc) -> Fallible<DOMString> { + fn GetOuterHTML(&self, can_gc: CanGc) -> Fallible<TrustedHTMLOrNullIsEmptyString> { // FIXME: This should use the fragment serialization algorithm, which takes // care of distinguishing between html/xml documents let result = if self.owner_document().is_html_document() { @@ -3186,27 +3229,39 @@ impl ElementMethods<crate::DomTypeHolder> for Element { self.upcast::<Node>().xml_serialize(XmlIncludeNode) }; - Ok(result) + Ok(TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(result)) } /// <https://html.spec.whatwg.org/multipage/#dom-element-outerhtml> - fn SetOuterHTML(&self, value: DOMString, can_gc: CanGc) -> ErrorResult { + fn SetOuterHTML(&self, value: TrustedHTMLOrNullIsEmptyString, can_gc: CanGc) -> ErrorResult { + // Step 1: Let compliantString be the result of invoking the + // Get Trusted Type compliant string algorithm with TrustedHTML, + // this's relevant global object, the given value, "Element outerHTML", and "script". + let value = DOMString::from(TrustedHTML::get_trusted_script_compliant_string( + &self.owner_global(), + value.convert(), + "Element", + "outerHTML", + can_gc, + )?); let context_document = self.owner_document(); let context_node = self.upcast::<Node>(); - // Step 1. + // Step 2: Let parent be this's parent. let context_parent = match context_node.GetParentNode() { None => { - // Step 2. + // Step 3: If parent is null, return. There would be no way to + // obtain a reference to the nodes created even if the remaining steps were run. return Ok(()); }, Some(parent) => parent, }; let parent = match context_parent.type_id() { - // Step 3. + // Step 4: If parent is a Document, throw a "NoModificationAllowedError" DOMException. NodeTypeId::Document(_) => return Err(Error::NoModificationAllowed), - // Step 4. + // Step 5: If parent is a DocumentFragment, set parent to the result of + // creating an element given this's node document, "body", and the HTML namespace. NodeTypeId::DocumentFragment(_) => { let body_elem = Element::create( QualName::new(None, ns!(html), local_name!("body")), @@ -3222,9 +3277,10 @@ impl ElementMethods<crate::DomTypeHolder> for Element { _ => context_node.GetParentElement().unwrap(), }; - // Step 5. + // Step 6: Let fragment be the result of invoking the + // fragment parsing algorithm steps given parent and compliantString. let frag = parent.parse_fragment(value, can_gc)?; - // Step 6. + // Step 7: Replace this with fragment within this's parent. context_parent.ReplaceChild(frag.upcast(), context_node, can_gc)?; Ok(()) } @@ -3391,38 +3447,57 @@ impl ElementMethods<crate::DomTypeHolder> for Element { fn InsertAdjacentHTML( &self, position: DOMString, - text: DOMString, + text: TrustedHTMLOrString, can_gc: CanGc, ) -> ErrorResult { - // Step 1. + // Step 1: Let compliantString be the result of invoking the + // Get Trusted Type compliant string algorithm with TrustedHTML, + // this's relevant global object, string, "Element insertAdjacentHTML", and "script". + let text = DOMString::from(TrustedHTML::get_trusted_script_compliant_string( + &self.owner_global(), + text, + "Element", + "insertAdjacentHTML", + can_gc, + )?); let position = position.parse::<AdjacentPosition>()?; + // Step 2: Let context be null. + // Step 3: Use the first matching item from this list: let context = match position { + // If position is an ASCII case-insensitive match for the string "beforebegin" + // If position is an ASCII case-insensitive match for the string "afterend" AdjacentPosition::BeforeBegin | AdjacentPosition::AfterEnd => { match self.upcast::<Node>().GetParentNode() { + // Step 3.2: If context is null or a Document, throw a "NoModificationAllowedError" DOMException. Some(ref node) if node.is::<Document>() => { return Err(Error::NoModificationAllowed); }, None => return Err(Error::NoModificationAllowed), + // Step 3.1: Set context to this's parent. Some(node) => node, } }, + // If position is an ASCII case-insensitive match for the string "afterbegin" + // If position is an ASCII case-insensitive match for the string "beforeend" AdjacentPosition::AfterBegin | AdjacentPosition::BeforeEnd => { + // Set context to this. DomRoot::from_ref(self.upcast::<Node>()) }, }; - // Step 2. + // Step 4. let context = Element::fragment_parsing_context( &context.owner_doc(), context.downcast::<Element>(), can_gc, ); - // Step 3. + // Step 5: Let fragment be the result of invoking the + // fragment parsing algorithm steps with context and compliantString. let fragment = context.parse_fragment(text, can_gc)?; - // Step 4. + // Step 6. self.insert_adjacent(position, fragment.upcast(), can_gc) .map(|_| ()) } diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index 902d4622db9..55db2e4d248 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -3562,10 +3562,6 @@ impl GlobalScopeHelpers<crate::DomTypeHolder> for GlobalScope { GlobalScope::from_reflector(reflector, realm) } - unsafe fn from_object_maybe_wrapped(obj: *mut JSObject, cx: *mut JSContext) -> DomRoot<Self> { - GlobalScope::from_object_maybe_wrapped(obj, cx) - } - fn origin(&self) -> &MutableOrigin { GlobalScope::origin(self) } diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 1622cf57b79..91a4e1b1359 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -547,6 +547,7 @@ pub(crate) mod submitevent; pub(crate) mod subtlecrypto; pub(crate) mod svgelement; pub(crate) mod svggraphicselement; +pub(crate) mod svgimageelement; pub(crate) mod svgsvgelement; pub(crate) mod testbinding; pub(crate) mod testbindingiterable; diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index ca785773b48..5f08abce354 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -4207,6 +4207,9 @@ impl From<ElementTypeIdWrapper> for LayoutElementType { LayoutElementType::HTMLTextAreaElement }, ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement( + SVGGraphicsElementTypeId::SVGImageElement, + )) => LayoutElementType::SVGImageElement, + ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement( SVGGraphicsElementTypeId::SVGSVGElement, )) => LayoutElementType::SVGSVGElement, _ => LayoutElementType::Element, diff --git a/components/script/dom/promise.rs b/components/script/dom/promise.rs index 80b62f161bc..0efffbe6fe2 100644 --- a/components/script/dom/promise.rs +++ b/components/script/dom/promise.rs @@ -29,7 +29,6 @@ use js::rust::wrappers::{ ResolvePromise, SetAnyPromiseIsHandled, SetPromiseUserInputEventHandlingState, }; use js::rust::{HandleObject, HandleValue, MutableHandleObject, Runtime}; -use script_bindings::interfaces::PromiseHelpers; use crate::dom::bindings::conversions::root_from_object; use crate::dom::bindings::error::{Error, ErrorToJsval}; @@ -388,16 +387,6 @@ fn create_native_handler_function( } } -impl PromiseHelpers<crate::DomTypeHolder> for Promise { - fn new_resolved( - global: &GlobalScope, - cx: SafeJSContext, - value: impl ToJSValConvertible, - ) -> Rc<Promise> { - Promise::new_resolved(global, cx, value, CanGc::note()) - } -} - impl FromJSValConvertibleRc for Promise { #[allow(unsafe_code)] unsafe fn from_jsval( @@ -407,16 +396,12 @@ impl FromJSValConvertibleRc for Promise { if value.get().is_null() { return Ok(ConversionResult::Failure("null not allowed".into())); } - if !value.get().is_object() { - return Ok(ConversionResult::Failure("not an object".into())); - } - rooted!(in(cx) let obj = value.get().to_object()); let cx = SafeJSContext::from_ptr(cx); let in_realm_proof = AlreadyInRealm::assert_for_cx(cx); let global_scope = GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof)); - let promise = Promise::new_resolved(&global_scope, cx, *obj, CanGc::note()); + let promise = Promise::new_resolved(&global_scope, cx, value, CanGc::note()); Ok(ConversionResult::Success(promise)) } } diff --git a/components/script/dom/readablestream.rs b/components/script/dom/readablestream.rs index 4982bfa32e3..d631a01e1e7 100644 --- a/components/script/dom/readablestream.rs +++ b/components/script/dom/readablestream.rs @@ -11,6 +11,7 @@ use std::rc::Rc; use base::id::{MessagePortId, MessagePortIndex}; use constellation_traits::MessagePortImpl; use dom_struct::dom_struct; +use ipc_channel::ipc::IpcSharedMemory; use js::conversions::ToJSValConvertible; use js::jsapi::{Heap, JSObject}; use js::jsval::{JSVal, NullValue, ObjectValue, UndefinedValue}; @@ -1131,12 +1132,14 @@ impl ReadableStream { /// Return bytes for synchronous use, if the stream has all data in memory. /// Useful for native source integration only. - pub(crate) fn get_in_memory_bytes(&self) -> Option<Vec<u8>> { + pub(crate) fn get_in_memory_bytes(&self) -> Option<IpcSharedMemory> { match self.controller.borrow().as_ref() { Some(ControllerType::Default(controller)) => controller .get() .expect("Stream should have controller.") - .get_in_memory_bytes(), + .get_in_memory_bytes() + .as_deref() + .map(IpcSharedMemory::from_bytes), _ => { unreachable!("Getting in-memory bytes for a stream with a non-default controller") }, diff --git a/components/script/dom/svgelement.rs b/components/script/dom/svgelement.rs index 9c8b990826d..0f36d942f3e 100644 --- a/components/script/dom/svgelement.rs +++ b/components/script/dom/svgelement.rs @@ -82,6 +82,9 @@ impl SVGElementMethods<crate::DomTypeHolder> for SVGElement { }) } + // <https://html.spec.whatwg.org/multipage/#globaleventhandlers> + global_event_handlers!(); + // FIXME: The nonce should be stored in an internal slot instead of an // attribute (https://html.spec.whatwg.org/multipage/#cryptographicnonce) // https://html.spec.whatwg.org/multipage/#dom-noncedelement-nonce diff --git a/components/script/dom/svgimageelement.rs b/components/script/dom/svgimageelement.rs new file mode 100644 index 00000000000..17a5a9149d8 --- /dev/null +++ b/components/script/dom/svgimageelement.rs @@ -0,0 +1,96 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use dom_struct::dom_struct; +use html5ever::{LocalName, Prefix, local_name, ns}; +use js::rust::HandleObject; +use style::attr::AttrValue; + +use crate::dom::attr::Attr; +use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::str::DOMString; +use crate::dom::document::Document; +use crate::dom::element::AttributeMutation; +use crate::dom::node::{Node, NodeTraits}; +use crate::dom::svggraphicselement::SVGGraphicsElement; +use crate::dom::virtualmethods::VirtualMethods; +use crate::script_runtime::CanGc; + +/// <https://svgwg.org/svg2-draft/embedded.html#Placement> +const DEFAULT_WIDTH: u32 = 300; +const DEFAULT_HEIGHT: u32 = 150; + +#[dom_struct] +pub(crate) struct SVGImageElement { + svggraphicselement: SVGGraphicsElement, +} + +impl SVGImageElement { + fn new_inherited( + local_name: LocalName, + prefix: Option<Prefix>, + document: &Document, + ) -> SVGImageElement { + SVGImageElement { + svggraphicselement: SVGGraphicsElement::new_inherited(local_name, prefix, document), + } + } + + #[cfg_attr(crown, allow(crown::unrooted_must_root))] + pub(crate) fn new( + local_name: LocalName, + prefix: Option<Prefix>, + document: &Document, + proto: Option<HandleObject>, + can_gc: CanGc, + ) -> DomRoot<SVGImageElement> { + Node::reflect_node_with_proto( + Box::new(SVGImageElement::new_inherited(local_name, prefix, document)), + document, + proto, + can_gc, + ) + } + + /// <https://svgwg.org/svg2-draft/linking.html#processingURL> + fn fetch_image_resource(&self) { + // TODO: Process and fetch the image resource (as HTMLImageElement). + // Reject any resource fetching request immediately. + self.owner_global() + .task_manager() + .dom_manipulation_task_source() + .queue_simple_event(self.upcast(), atom!("error")); + } +} + +impl VirtualMethods for SVGImageElement { + fn super_type(&self) -> Option<&dyn VirtualMethods> { + Some(self.upcast::<SVGGraphicsElement>() as &dyn VirtualMethods) + } + + fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) { + self.super_type() + .unwrap() + .attribute_mutated(attr, mutation, can_gc); + if attr.local_name() == &local_name!("href") && + matches!(attr.namespace(), &ns!() | &ns!(xlink)) + { + if let AttributeMutation::Set(_) = mutation { + self.fetch_image_resource(); + } + } + } + + fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue { + match *name { + local_name!("width") => AttrValue::from_u32(value.into(), DEFAULT_WIDTH), + local_name!("height") => AttrValue::from_u32(value.into(), DEFAULT_HEIGHT), + _ => self + .super_type() + .unwrap() + .parse_plain_attribute(name, value), + } + } +} diff --git a/components/script/dom/transformstream.rs b/components/script/dom/transformstream.rs index 023fe7ac483..0251498980d 100644 --- a/components/script/dom/transformstream.rs +++ b/components/script/dom/transformstream.rs @@ -3,9 +3,12 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use std::cell::Cell; +use std::collections::HashMap; use std::ptr::{self}; use std::rc::Rc; +use base::id::{MessagePortId, MessagePortIndex}; +use constellation_traits::MessagePortImpl; use dom_struct::dom_struct; use js::jsapi::{Heap, IsPromiseObject, JSObject}; use js::jsval::{JSVal, ObjectValue, UndefinedValue}; @@ -14,6 +17,9 @@ use script_bindings::callback::ExceptionHandling; use script_bindings::realms::InRealm; use super::bindings::codegen::Bindings::QueuingStrategyBinding::QueuingStrategySize; +use super::bindings::structuredclone::StructuredData; +use super::bindings::transferable::Transferable; +use super::messageport::MessagePort; use super::promisenativehandler::Callback; use super::types::{TransformStreamDefaultController, WritableStream}; use crate::dom::bindings::cell::DomRefCell; @@ -997,3 +1003,103 @@ impl TransformStreamMethods<crate::DomTypeHolder> for TransformStream { self.writable.get().expect("writable stream is not set") } } + +/// <https://streams.spec.whatwg.org/#ts-transfer> +impl Transferable for TransformStream { + type Index = MessagePortIndex; + type Data = MessagePortImpl; + + fn transfer(&self) -> Result<(MessagePortId, MessagePortImpl), ()> { + let global = self.global(); + let realm = enter_realm(&*global); + let comp = InRealm::Entered(&realm); + let cx = GlobalScope::get_cx(); + let can_gc = CanGc::note(); + + // Let readable be value.[[readable]]. + let readable = self.get_readable(); + + // Let writable be value.[[writable]]. + let writable = self.get_writable(); + + // If ! IsReadableStreamLocked(readable) is true, throw a "DataCloneError" DOMException. + if readable.is_locked() { + return Err(()); + } + + // If ! IsWritableStreamLocked(writable) is true, throw a "DataCloneError" DOMException. + if writable.is_locked() { + return Err(()); + } + + // Create the shared port pair + let port_1 = MessagePort::new(&global, can_gc); + global.track_message_port(&port_1, None); + let port_2 = MessagePort::new(&global, can_gc); + global.track_message_port(&port_2, None); + global.entangle_ports(*port_1.message_port_id(), *port_2.message_port_id()); + + // Create a proxy WritableStream wired to port_1 + let proxy_writable = WritableStream::new_with_proto(&global, None, can_gc); + proxy_writable.setup_cross_realm_transform_writable(cx, &port_1, can_gc); + + // Pipe readable into the proxy writable (→ port_1) + let pipe1 = readable.pipe_to( + cx, + &global, + &proxy_writable, + false, + false, + false, + comp, + can_gc, + ); + pipe1.set_promise_is_handled(); + + // Create a proxy ReadableStream wired to port_1 + let proxy_readable = ReadableStream::new_with_proto(&global, None, can_gc); + proxy_readable.setup_cross_realm_transform_readable(cx, &port_1, can_gc); + + // Pipe proxy readable (← port_1) into writable + let pipe2 = + proxy_readable.pipe_to(cx, &global, &writable, false, false, false, comp, can_gc); + pipe2.set_promise_is_handled(); + + // Set dataHolder.[[readable]] to ! StructuredSerializeWithTransfer(readable, « readable »). + // Set dataHolder.[[writable]] to ! StructuredSerializeWithTransfer(writable, « writable »). + port_2.transfer() + } + + fn transfer_receive( + owner: &GlobalScope, + id: MessagePortId, + port_impl: MessagePortImpl, + ) -> Result<DomRoot<Self>, ()> { + let can_gc = CanGc::note(); + + // Let readableRecord be ! StructuredDeserializeWithTransfer(dataHolder.[[readable]], the current Realm). + // Set value.[[readable]] to readableRecord.[[Deserialized]]. + let readable = ReadableStream::transfer_receive(owner, id, port_impl.clone())?; + + // Let writableRecord be ! StructuredDeserializeWithTransfer(dataHolder.[[writable]], the current Realm). + let writable = WritableStream::transfer_receive(owner, id, port_impl)?; + + // Set value.[[readable]] to readableRecord.[[Deserialized]]. + // Set value.[[writable]] to writableRecord.[[Deserialized]]. + // Set value.[[backpressure]], value.[[backpressureChangePromise]], and value.[[controller]] to undefined. + let stream = TransformStream::new_with_proto(owner, None, can_gc); + stream.readable.set(Some(&readable)); + stream.writable.set(Some(&writable)); + + Ok(stream) + } + + 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, + } + } +} diff --git a/components/script/dom/trustedhtml.rs b/components/script/dom/trustedhtml.rs index 8508f28c150..d1ca3cd5e71 100644 --- a/components/script/dom/trustedhtml.rs +++ b/components/script/dom/trustedhtml.rs @@ -6,8 +6,11 @@ use std::fmt; use dom_struct::dom_struct; +use crate::conversions::Convert; use crate::dom::bindings::codegen::Bindings::TrustedHTMLBinding::TrustedHTMLMethods; -use crate::dom::bindings::codegen::UnionTypes::TrustedHTMLOrString; +use crate::dom::bindings::codegen::UnionTypes::{ + TrustedHTMLOrNullIsEmptyString, TrustedHTMLOrString, +}; use crate::dom::bindings::error::Fallible; use crate::dom::bindings::reflector::{Reflector, reflect_dom_object}; use crate::dom::bindings::root::DomRoot; @@ -80,3 +83,16 @@ impl TrustedHTMLMethods<crate::DomTypeHolder> for TrustedHTML { DOMString::from(&*self.data) } } + +impl Convert<TrustedHTMLOrString> for TrustedHTMLOrNullIsEmptyString { + fn convert(self) -> TrustedHTMLOrString { + match self { + TrustedHTMLOrNullIsEmptyString::TrustedHTML(trusted_html) => { + TrustedHTMLOrString::TrustedHTML(trusted_html) + }, + TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(str) => { + TrustedHTMLOrString::String(str) + }, + } + } +} diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs index 57ecba7b172..1d992b1f301 100644 --- a/components/script/dom/virtualmethods.rs +++ b/components/script/dom/virtualmethods.rs @@ -61,6 +61,7 @@ use crate::dom::htmlvideoelement::HTMLVideoElement; use crate::dom::node::{BindContext, ChildrenMutation, CloneChildrenFlag, Node, UnbindContext}; use crate::dom::shadowroot::ShadowRoot; use crate::dom::svgelement::SVGElement; +use crate::dom::svgimageelement::SVGImageElement; use crate::dom::svgsvgelement::SVGSVGElement; /// Trait to allow DOM nodes to opt-in to overriding (or adding to) common @@ -299,6 +300,9 @@ pub(crate) fn vtable_for(node: &Node) -> &dyn VirtualMethods { node.downcast::<HTMLTitleElement>().unwrap() as &dyn VirtualMethods }, NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement( + SVGGraphicsElementTypeId::SVGImageElement, + ))) => node.downcast::<SVGImageElement>().unwrap() as &dyn VirtualMethods, + NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement( SVGGraphicsElementTypeId::SVGSVGElement, ))) => node.downcast::<SVGSVGElement>().unwrap() as &dyn VirtualMethods, NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGElement)) => { |