aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/body.rs14
-rw-r--r--components/script/dom/attr.rs10
-rw-r--r--components/script/dom/bindings/structuredclone.rs7
-rw-r--r--components/script/dom/create.rs2
-rw-r--r--components/script/dom/element.rs12
-rw-r--r--components/script/dom/globalscope.rs4
-rw-r--r--components/script/dom/mod.rs1
-rw-r--r--components/script/dom/node.rs3
-rw-r--r--components/script/dom/promise.rs17
-rw-r--r--components/script/dom/readablestream.rs7
-rw-r--r--components/script/dom/svgelement.rs3
-rw-r--r--components/script/dom/svgimageelement.rs96
-rw-r--r--components/script/dom/transformstream.rs106
-rw-r--r--components/script/dom/virtualmethods.rs4
-rw-r--r--components/script/messaging.rs1
-rw-r--r--components/script/script_thread.rs57
16 files changed, 305 insertions, 39 deletions
diff --git a/components/script/body.rs b/components/script/body.rs
index 113f3ac7adb..cc7870a0845 100644
--- a/components/script/body.rs
+++ b/components/script/body.rs
@@ -7,7 +7,7 @@ use std::{ptr, slice, str};
use constellation_traits::BlobImpl;
use encoding_rs::{Encoding, UTF_8};
-use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
+use ipc_channel::ipc::{self, IpcReceiver, IpcSender, IpcSharedMemory};
use ipc_channel::router::ROUTER;
use js::jsapi::{Heap, JS_ClearPendingException, JSObject, Value as JSValue};
use js::jsval::{JSVal, UndefinedValue};
@@ -73,7 +73,7 @@ struct TransmitBodyConnectHandler {
task_source: SendableTaskSource,
bytes_sender: Option<IpcSender<BodyChunkResponse>>,
control_sender: IpcSender<BodyChunkRequest>,
- in_memory: Option<Vec<u8>>,
+ in_memory: Option<IpcSharedMemory>,
in_memory_done: bool,
source: BodySource,
}
@@ -83,7 +83,7 @@ impl TransmitBodyConnectHandler {
stream: Trusted<ReadableStream>,
task_source: SendableTaskSource,
control_sender: IpcSender<BodyChunkRequest>,
- in_memory: Option<Vec<u8>>,
+ in_memory: Option<IpcSharedMemory>,
source: BodySource,
) -> TransmitBodyConnectHandler {
TransmitBodyConnectHandler {
@@ -160,7 +160,7 @@ impl TransmitBodyConnectHandler {
.bytes_sender
.as_ref()
.expect("No bytes sender to transmit source.")
- .send(BodyChunkResponse::Chunk(bytes.clone()));
+ .send(BodyChunkResponse::Chunk(bytes));
return;
}
warn!("Re-directs for file-based Blobs not supported yet.");
@@ -310,7 +310,11 @@ impl Callback for TransmitBodyPromiseHandler {
// Step 5.1 and 5.2, transmit chunk.
// Send the chunk to the body transmitter in net::http_loader::obtain_response.
// TODO: queue a fetch task on request to process request body for request.
- let _ = self.bytes_sender.send(BodyChunkResponse::Chunk(chunk));
+ let _ = self
+ .bytes_sender
+ .send(BodyChunkResponse::Chunk(IpcSharedMemory::from_bytes(
+ &chunk,
+ )));
}
}
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 f094d3b728a..a73c5347d70 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -65,7 +65,7 @@ use xml5ever::serialize::TraversalScope::{
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;
@@ -359,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();
}
}
@@ -1705,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);
}
}
@@ -1847,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())
@@ -1902,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,
@@ -2722,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())),
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/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)) => {
diff --git a/components/script/messaging.rs b/components/script/messaging.rs
index e0ea9e30af2..08d6fc841cf 100644
--- a/components/script/messaging.rs
+++ b/components/script/messaging.rs
@@ -91,6 +91,7 @@ impl MixedMessage {
#[cfg(feature = "webgpu")]
ScriptThreadMessage::SetWebGPUPort(..) => None,
ScriptThreadMessage::SetScrollStates(id, ..) => Some(*id),
+ ScriptThreadMessage::EvaluateJavaScript(id, _, _) => Some(*id),
},
MixedMessage::FromScript(inner_msg) => match inner_msg {
MainThreadScriptMsg::Common(CommonScriptMsg::Task(_, _, pipeline_id, _)) => {
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index d6ab18be49b..4815e6feae1 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -50,9 +50,9 @@ use devtools_traits::{
};
use embedder_traits::user_content_manager::UserContentManager;
use embedder_traits::{
- CompositorHitTestResult, EmbedderMsg, FocusSequenceNumber, InputEvent, MediaSessionActionType,
- MouseButton, MouseButtonAction, MouseButtonEvent, Theme, ViewportDetails,
- WebDriverScriptCommand,
+ CompositorHitTestResult, EmbedderMsg, FocusSequenceNumber, InputEvent,
+ JavaScriptEvaluationError, JavaScriptEvaluationId, MediaSessionActionType, MouseButton,
+ MouseButtonAction, MouseButtonEvent, Theme, ViewportDetails, WebDriverScriptCommand,
};
use euclid::Point2D;
use euclid::default::Rect;
@@ -156,6 +156,7 @@ use crate::script_runtime::{
};
use crate::task_queue::TaskQueue;
use crate::task_source::{SendableTaskSource, TaskSourceName};
+use crate::webdriver_handlers::jsval_to_webdriver;
use crate::{devtools, webdriver_handlers};
thread_local!(static SCRIPT_THREAD_ROOT: Cell<Option<*const ScriptThread>> = const { Cell::new(None) });
@@ -1878,6 +1879,9 @@ impl ScriptThread {
ScriptThreadMessage::SetScrollStates(pipeline_id, scroll_states) => {
self.handle_set_scroll_states(pipeline_id, scroll_states)
},
+ ScriptThreadMessage::EvaluateJavaScript(pipeline_id, evaluation_id, script) => {
+ self.handle_evaluate_javascript(pipeline_id, evaluation_id, script, can_gc);
+ },
}
}
@@ -3815,6 +3819,53 @@ impl ScriptThread {
)
}
}
+
+ fn handle_evaluate_javascript(
+ &self,
+ pipeline_id: PipelineId,
+ evaluation_id: JavaScriptEvaluationId,
+ script: String,
+ can_gc: CanGc,
+ ) {
+ let Some(window) = self.documents.borrow().find_window(pipeline_id) else {
+ let _ = self.senders.pipeline_to_constellation_sender.send((
+ pipeline_id,
+ ScriptToConstellationMessage::FinishJavaScriptEvaluation(
+ evaluation_id,
+ Err(JavaScriptEvaluationError::WebViewNotReady),
+ ),
+ ));
+ return;
+ };
+
+ let global_scope = window.as_global_scope();
+ let realm = enter_realm(global_scope);
+ let context = window.get_cx();
+
+ rooted!(in(*context) let mut return_value = UndefinedValue());
+ global_scope.evaluate_js_on_global_with_result(
+ &script,
+ return_value.handle_mut(),
+ ScriptFetchOptions::default_classic_script(global_scope),
+ global_scope.api_base_url(),
+ can_gc,
+ );
+ let result = match jsval_to_webdriver(
+ context,
+ global_scope,
+ return_value.handle(),
+ (&realm).into(),
+ can_gc,
+ ) {
+ Ok(ref value) => Ok(value.into()),
+ Err(_) => Err(JavaScriptEvaluationError::SerializationError),
+ };
+
+ let _ = self.senders.pipeline_to_constellation_sender.send((
+ pipeline_id,
+ ScriptToConstellationMessage::FinishJavaScriptEvaluation(evaluation_id, result),
+ ));
+ }
}
impl Drop for ScriptThread {