aboutsummaryrefslogtreecommitdiffstats
path: root/components/script_bindings
diff options
context:
space:
mode:
Diffstat (limited to 'components/script_bindings')
-rw-r--r--components/script_bindings/codegen/Bindings.conf12
-rw-r--r--components/script_bindings/codegen/CodegenRust.py13
-rw-r--r--components/script_bindings/error.rs2
-rw-r--r--components/script_bindings/import.rs9
-rw-r--r--components/script_bindings/root.rs2
-rw-r--r--components/script_bindings/str.rs65
-rw-r--r--components/script_bindings/utils.rs106
-rw-r--r--components/script_bindings/webidls/CSSStyleSheet.webidl1
-rw-r--r--components/script_bindings/webidls/HTMLScriptElement.webidl4
-rw-r--r--components/script_bindings/webidls/Response.webidl1
-rw-r--r--components/script_bindings/webidls/Window.webidl3
11 files changed, 181 insertions, 37 deletions
diff --git a/components/script_bindings/codegen/Bindings.conf b/components/script_bindings/codegen/Bindings.conf
index f9ab745e4ea..c50bc31a7f5 100644
--- a/components/script_bindings/codegen/Bindings.conf
+++ b/components/script_bindings/codegen/Bindings.conf
@@ -416,7 +416,7 @@ DOMInterfaces = {
},
'HTMLScriptElement': {
- 'canGc': ['SetAsync', 'SetCrossOrigin', 'SetText']
+ 'canGc': ['SetAsync', 'SetCrossOrigin', 'SetSrc', 'SetText']
},
'HTMLSelectElement': {
@@ -551,7 +551,7 @@ DOMInterfaces = {
},
'Response': {
- 'canGc': ['Error', 'Redirect', 'Clone', 'Text', 'Blob', 'FormData', 'Json', 'ArrayBuffer', 'Headers', 'Bytes'],
+ 'canGc': ['Error', 'Redirect', 'Clone', 'CreateFromJson', 'Text', 'Blob', 'FormData', 'Json', 'ArrayBuffer', 'Headers', 'Bytes'],
},
'RTCPeerConnection': {
@@ -642,8 +642,8 @@ DOMInterfaces = {
},
'Window': {
- 'canGc': ['Stop', 'Fetch', 'Scroll', 'Scroll_','ScrollBy', 'ScrollBy_', 'Stop', 'Fetch', 'Open', 'CreateImageBitmap', 'TrustedTypes'],
- 'inRealms': ['Fetch', 'GetOpener'],
+ 'canGc': ['Stop', 'Fetch', 'Scroll', 'Scroll_','ScrollBy', 'ScrollBy_', 'Stop', 'Fetch', 'Open', 'CreateImageBitmap', 'TrustedTypes', 'WebdriverCallback', 'WebdriverException'],
+ 'inRealms': ['Fetch', 'GetOpener', 'WebdriverCallback', 'WebdriverException'],
'additionalTraits': ['crate::interfaces::WindowHelpers'],
},
@@ -764,6 +764,10 @@ DOMInterfaces = {
'inRealms': ['Abort', 'Close', 'Write'],
},
+'TransformStreamDefaultController': {
+ 'canGc': ['Enqueue', 'Error', 'Terminate'],
+},
+
'WorkerNavigator': {
'canGc': ['Languages'],
},
diff --git a/components/script_bindings/codegen/CodegenRust.py b/components/script_bindings/codegen/CodegenRust.py
index 107e047ea3b..48f024be70f 100644
--- a/components/script_bindings/codegen/CodegenRust.py
+++ b/components/script_bindings/codegen/CodegenRust.py
@@ -2405,15 +2405,22 @@ class CGDOMJSClass(CGThing):
"flags": "JSCLASS_FOREGROUND_FINALIZE",
"name": str_to_cstr_ptr(self.descriptor.interface.identifier.name),
"resolveHook": "None",
+ "mayResolveHook": "None",
"slots": "1",
"traceHook": f"{TRACE_HOOK_NAME}::<D>",
}
if self.descriptor.isGlobal():
assert not self.descriptor.weakReferenceable
- args["enumerateHook"] = "Some(enumerate_global::<D>)"
args["flags"] = "JSCLASS_IS_GLOBAL | JSCLASS_DOM_GLOBAL | JSCLASS_FOREGROUND_FINALIZE"
args["slots"] = "JSCLASS_GLOBAL_SLOT_COUNT + 1"
- args["resolveHook"] = "Some(resolve_global::<D>)"
+ if self.descriptor.interface.getExtendedAttribute("NeedResolve"):
+ args["enumerateHook"] = "Some(enumerate_window::<D>)"
+ args["resolveHook"] = "Some(resolve_window::<D>)"
+ args["mayResolveHook"] = "Some(may_resolve_window::<D>)"
+ else:
+ args["enumerateHook"] = "Some(enumerate_global)"
+ args["resolveHook"] = "Some(resolve_global)"
+ args["mayResolveHook"] = "Some(may_resolve_global)"
args["traceHook"] = "js::jsapi::JS_GlobalObjectTraceHook"
elif self.descriptor.weakReferenceable:
args["slots"] = "2"
@@ -2427,7 +2434,7 @@ pub(crate) fn init_class_ops<D: DomTypes>() {{
enumerate: None,
newEnumerate: {args['enumerateHook']},
resolve: {args['resolveHook']},
- mayResolve: None,
+ mayResolve: {args['mayResolveHook']},
finalize: Some({args['finalizeHook']}),
call: None,
construct: None,
diff --git a/components/script_bindings/error.rs b/components/script_bindings/error.rs
index 8424ff0fa95..a95d0b0b78c 100644
--- a/components/script_bindings/error.rs
+++ b/components/script_bindings/error.rs
@@ -59,6 +59,8 @@ pub enum Error {
Data,
/// OperationError DOMException
Operation,
+ /// NotAllowedError DOMException
+ NotAllowed,
/// TypeError JavaScript Error
Type(String),
diff --git a/components/script_bindings/import.rs b/components/script_bindings/import.rs
index 65e9ee30e1d..16cc92f07bf 100644
--- a/components/script_bindings/import.rs
+++ b/components/script_bindings/import.rs
@@ -127,10 +127,11 @@ pub(crate) mod module {
pub(crate) use crate::script_runtime::CanGc;
pub(crate) use crate::utils::{
AsVoidPtr, DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, DOMClass, DOMJSClass, JSCLASS_DOM_GLOBAL,
- ProtoOrIfaceArray, enumerate_global, exception_to_promise, generic_getter,
- generic_lenient_getter, generic_lenient_setter, generic_method, generic_setter,
- generic_static_promise_method, get_array_index_from_id, get_property_on_prototype,
- has_property_on_prototype, resolve_global, trace_global,
+ ProtoOrIfaceArray, enumerate_global, enumerate_window, exception_to_promise,
+ generic_getter, generic_lenient_getter, generic_lenient_setter, generic_method,
+ generic_setter, generic_static_promise_method, get_array_index_from_id,
+ get_property_on_prototype, has_property_on_prototype, may_resolve_global,
+ may_resolve_window, resolve_global, resolve_window, trace_global,
};
pub(crate) use crate::weakref::DOM_WEAK_SLOT;
pub(crate) use crate::{JSTraceable, proxyhandler};
diff --git a/components/script_bindings/root.rs b/components/script_bindings/root.rs
index 51bc979908f..3d0378f0df1 100644
--- a/components/script_bindings/root.rs
+++ b/components/script_bindings/root.rs
@@ -412,7 +412,7 @@ impl RootCollection {
.rposition(|r| std::ptr::addr_eq(*r as *const (), object as *const ()))
{
Some(idx) => {
- roots.remove(idx);
+ roots.swap_remove(idx);
},
None => panic!("Can't remove a root that was never rooted!"),
}
diff --git a/components/script_bindings/str.rs b/components/script_bindings/str.rs
index 09d48512f3e..0ef6e0c528a 100644
--- a/components/script_bindings/str.rs
+++ b/components/script_bindings/str.rs
@@ -10,14 +10,19 @@ use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::str::FromStr;
use std::sync::LazyLock;
-use std::{fmt, ops, str};
+use std::{fmt, ops, slice, str};
use cssparser::CowRcStr;
use html5ever::{LocalName, Namespace};
+use js::rust::wrappers::ToJSON;
+use js::rust::{HandleObject, HandleValue};
use num_traits::Zero;
use regex::Regex;
use stylo_atoms::Atom;
+use crate::error::Error;
+use crate::script_runtime::JSContext as SafeJSContext;
+
/// Encapsulates the IDL `ByteString` type.
#[derive(Clone, Debug, Default, Eq, JSTraceable, MallocSizeOf, PartialEq)]
pub struct ByteString(Vec<u8>);
@@ -293,6 +298,64 @@ impl DOMString {
}
}
+/// Because this converts to a DOMString it becomes UTF-8 encoded which is closer to
+/// the spec definition of <https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-json-bytes>
+/// but we generally do not operate on anything that is truly a WTF-16 string.
+///
+/// <https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-a-json-string>
+pub fn serialize_jsval_to_json_utf8(
+ cx: SafeJSContext,
+ data: HandleValue,
+) -> Result<DOMString, Error> {
+ #[repr(C)]
+ struct ToJSONCallbackData {
+ string: Option<String>,
+ }
+
+ let mut out_str = ToJSONCallbackData { string: None };
+
+ #[allow(unsafe_code)]
+ unsafe extern "C" fn write_callback(
+ string: *const u16,
+ len: u32,
+ data: *mut std::ffi::c_void,
+ ) -> bool {
+ let data = data as *mut ToJSONCallbackData;
+ let string_chars = slice::from_raw_parts(string, len as usize);
+ (*data)
+ .string
+ .get_or_insert_with(Default::default)
+ .push_str(&String::from_utf16_lossy(string_chars));
+ true
+ }
+
+ // 1. Let result be ? Call(%JSON.stringify%, undefined, « value »).
+ unsafe {
+ let stringify_result = ToJSON(
+ *cx,
+ data,
+ HandleObject::null(),
+ HandleValue::null(),
+ Some(write_callback),
+ &mut out_str as *mut ToJSONCallbackData as *mut _,
+ );
+ // Note: ToJSON returns false when a JS error is thrown, so we need to return
+ // JSFailed to propagate the raised exception
+ if !stringify_result {
+ return Err(Error::JSFailed);
+ }
+ }
+
+ // 2. If result is undefined, then throw a TypeError.
+ // Note: ToJSON will not call the callback if the data cannot be serialized.
+ // 3. Assert: result is a string.
+ // 4. Return result.
+ out_str
+ .string
+ .map(Into::into)
+ .ok_or_else(|| Error::Type("unable to serialize JSON".to_owned()))
+}
+
impl Borrow<str> for DOMString {
#[inline]
fn borrow(&self) -> &str {
diff --git a/components/script_bindings/utils.rs b/components/script_bindings/utils.rs
index 03a5783958e..fa4982b9904 100644
--- a/components/script_bindings/utils.rs
+++ b/components/script_bindings/utils.rs
@@ -18,9 +18,10 @@ use js::jsapi::{
GetLinearStringLength, GetNonCCWObjectGlobal, HandleId as RawHandleId,
HandleObject as RawHandleObject, Heap, JS_AtomizeStringN, JS_ClearPendingException,
JS_DeprecatedStringHasLatin1Chars, JS_GetLatin1StringCharsAndLength, JS_IsExceptionPending,
- JS_IsGlobalObject, JS_NewEnumerateStandardClasses, JS_ResolveStandardClass, JSAtom, JSContext,
- JSJitInfo, JSObject, JSTracer, MutableHandleIdVector as RawMutableHandleIdVector,
- MutableHandleValue as RawMutableHandleValue, ObjectOpResult, StringIsArrayIndex,
+ JS_IsGlobalObject, JS_MayResolveStandardClass, JS_NewEnumerateStandardClasses,
+ JS_ResolveStandardClass, JSAtom, JSAtomState, JSContext, JSJitInfo, JSObject, JSTracer,
+ MutableHandleIdVector as RawMutableHandleIdVector, MutableHandleValue as RawMutableHandleValue,
+ ObjectOpResult, PropertyKey, StringIsArrayIndex, jsid,
};
use js::jsid::StringId;
use js::jsval::{JSVal, UndefinedValue};
@@ -30,7 +31,7 @@ use js::rust::wrappers::{
JS_SetPendingException, JS_SetProperty,
};
use js::rust::{
- HandleId, HandleObject, HandleValue, MutableHandleValue, ToString, get_object_class,
+ HandleId, HandleObject, HandleValue, MutableHandleValue, Runtime, ToString, get_object_class,
};
use js::{JS_CALLEE, rooted};
use malloc_size_of::MallocSizeOfOps;
@@ -577,15 +578,25 @@ impl AsCCharPtrPtr for [u8] {
/// Enumerate lazy properties of a global object.
/// Modeled after <https://github.com/mozilla/gecko-dev/blob/3fd619f47/dom/bindings/BindingUtils.cpp#L2814>
-/// and <https://github.com/mozilla/gecko-dev/blob/3fd619f47/dom/base/nsGlobalWindowInner.cpp#3297>
-pub(crate) unsafe extern "C" fn enumerate_global<D: DomTypes>(
+pub(crate) unsafe extern "C" fn enumerate_global(
cx: *mut JSContext,
obj: RawHandleObject,
props: RawMutableHandleIdVector,
enumerable_only: bool,
) -> bool {
assert!(JS_IsGlobalObject(obj.get()));
- if !JS_NewEnumerateStandardClasses(cx, obj, props, enumerable_only) {
+ JS_NewEnumerateStandardClasses(cx, obj, props, enumerable_only)
+}
+
+/// Enumerate lazy properties of a global object that is a Window.
+/// <https://github.com/mozilla/gecko-dev/blob/3fd619f47/dom/base/nsGlobalWindowInner.cpp#3297>
+pub(crate) unsafe extern "C" fn enumerate_window<D: DomTypes>(
+ cx: *mut JSContext,
+ obj: RawHandleObject,
+ props: RawMutableHandleIdVector,
+ enumerable_only: bool,
+) -> bool {
+ if !enumerate_global(cx, obj, props, enumerable_only) {
return false;
}
@@ -610,34 +621,68 @@ pub(crate) unsafe extern "C" fn enumerate_global<D: DomTypes>(
true
}
+/// Returns true if the resolve hook for this global may resolve the provided id.
+/// <https://searchfox.org/mozilla-central/rev/f3c8c63a097b61bb1f01e13629b9514e09395947/dom/bindings/BindingUtils.cpp#2809>
+/// <https://searchfox.org/mozilla-central/rev/f3c8c63a097b61bb1f01e13629b9514e09395947/js/public/Class.h#283-291>
+pub(crate) unsafe extern "C" fn may_resolve_global(
+ names: *const JSAtomState,
+ id: PropertyKey,
+ maybe_obj: *mut JSObject,
+) -> bool {
+ JS_MayResolveStandardClass(names, id, maybe_obj)
+}
+
+/// Returns true if the resolve hook for this window may resolve the provided id.
+/// <https://searchfox.org/mozilla-central/rev/f3c8c63a097b61bb1f01e13629b9514e09395947/dom/base/nsGlobalWindowInner.cpp#3275>
+/// <https://searchfox.org/mozilla-central/rev/f3c8c63a097b61bb1f01e13629b9514e09395947/js/public/Class.h#283-291>
+pub(crate) unsafe extern "C" fn may_resolve_window<D: DomTypes>(
+ names: *const JSAtomState,
+ id: PropertyKey,
+ maybe_obj: *mut JSObject,
+) -> bool {
+ if may_resolve_global(names, id, maybe_obj) {
+ return true;
+ }
+
+ let cx = Runtime::get()
+ .expect("There must be a JSContext active")
+ .as_ptr();
+ let Ok(bytes) = latin1_bytes_from_id(cx, id) else {
+ return false;
+ };
+
+ <D as DomHelpers<D>>::interface_map().contains_key(bytes)
+}
+
/// Resolve a lazy global property, for interface objects and named constructors.
-pub(crate) unsafe extern "C" fn resolve_global<D: DomTypes>(
+pub(crate) unsafe extern "C" fn resolve_global(
cx: *mut JSContext,
obj: RawHandleObject,
id: RawHandleId,
rval: *mut bool,
) -> bool {
assert!(JS_IsGlobalObject(obj.get()));
- if !JS_ResolveStandardClass(cx, obj, id, rval) {
+ JS_ResolveStandardClass(cx, obj, id, rval)
+}
+
+/// Resolve a lazy global property for a Window global.
+pub(crate) unsafe extern "C" fn resolve_window<D: DomTypes>(
+ cx: *mut JSContext,
+ obj: RawHandleObject,
+ id: RawHandleId,
+ rval: *mut bool,
+) -> bool {
+ if !resolve_global(cx, obj, id, rval) {
return false;
}
+
if *rval {
return true;
}
- if !id.is_string() {
- *rval = false;
- return true;
- }
-
- let string = id.to_string();
- if !JS_DeprecatedStringHasLatin1Chars(string) {
+ let Ok(bytes) = latin1_bytes_from_id(cx, *id) else {
*rval = false;
return true;
- }
- let mut length = 0;
- let ptr = JS_GetLatin1StringCharsAndLength(cx, ptr::null(), string, &mut length);
- assert!(!ptr.is_null());
- let bytes = slice::from_raw_parts(ptr, length);
+ };
if let Some(interface) = <D as DomHelpers<D>>::interface_map().get(bytes) {
(interface.define)(SafeJSContext::from_ptr(cx), Handle::from_raw(obj));
@@ -647,3 +692,22 @@ pub(crate) unsafe extern "C" fn resolve_global<D: DomTypes>(
}
true
}
+
+/// Returns a slice of bytes corresponding to the bytes in the provided string id.
+/// Returns an error if the id is not a string, or the string contains non-latin1 characters.
+/// # Safety
+/// The slice is only valid as long as the original id is not garbage collected.
+unsafe fn latin1_bytes_from_id(cx: *mut JSContext, id: jsid) -> Result<&'static [u8], ()> {
+ if !id.is_string() {
+ return Err(());
+ }
+
+ let string = id.to_string();
+ if !JS_DeprecatedStringHasLatin1Chars(string) {
+ return Err(());
+ }
+ let mut length = 0;
+ let ptr = JS_GetLatin1StringCharsAndLength(cx, ptr::null(), string, &mut length);
+ assert!(!ptr.is_null());
+ Ok(slice::from_raw_parts(ptr, length))
+}
diff --git a/components/script_bindings/webidls/CSSStyleSheet.webidl b/components/script_bindings/webidls/CSSStyleSheet.webidl
index 1241b5c2769..302e7433300 100644
--- a/components/script_bindings/webidls/CSSStyleSheet.webidl
+++ b/components/script_bindings/webidls/CSSStyleSheet.webidl
@@ -11,6 +11,7 @@ interface CSSStyleSheet : StyleSheet {
[Throws, SameObject] readonly attribute CSSRuleList cssRules;
[Throws] unsigned long insertRule(DOMString rule, optional unsigned long index = 0);
[Throws] undefined deleteRule(unsigned long index);
+ [Throws] undefined replaceSync(USVString text);
};
dictionary CSSStyleSheetInit {
diff --git a/components/script_bindings/webidls/HTMLScriptElement.webidl b/components/script_bindings/webidls/HTMLScriptElement.webidl
index b79382dbbb8..6f02bb3cf47 100644
--- a/components/script_bindings/webidls/HTMLScriptElement.webidl
+++ b/components/script_bindings/webidls/HTMLScriptElement.webidl
@@ -7,8 +7,8 @@
interface HTMLScriptElement : HTMLElement {
[HTMLConstructor] constructor();
- [CEReactions]
- attribute USVString src;
+ [CEReactions, SetterThrows]
+ attribute (TrustedScriptURL or USVString) src;
[CEReactions]
attribute DOMString type;
[CEReactions]
diff --git a/components/script_bindings/webidls/Response.webidl b/components/script_bindings/webidls/Response.webidl
index 0ced0c13794..d37538d4b6b 100644
--- a/components/script_bindings/webidls/Response.webidl
+++ b/components/script_bindings/webidls/Response.webidl
@@ -9,6 +9,7 @@ interface Response {
[Throws] constructor(optional BodyInit? body = null, optional ResponseInit init = {});
[NewObject] static Response error();
[NewObject, Throws] static Response redirect(USVString url, optional unsigned short status = 302);
+ [NewObject, Throws, BinaryName="createFromJson"] static Response json(any data, optional ResponseInit init = {});
readonly attribute ResponseType type;
diff --git a/components/script_bindings/webidls/Window.webidl b/components/script_bindings/webidls/Window.webidl
index c7b6dde617d..81c442b119f 100644
--- a/components/script_bindings/webidls/Window.webidl
+++ b/components/script_bindings/webidls/Window.webidl
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// https://html.spec.whatwg.org/multipage/#window
-[Global=Window, Exposed=Window /*, LegacyUnenumerableNamedProperties */]
+[Global=Window, Exposed=Window, LegacyUnenumerableNamedProperties, NeedResolve]
/*sealed*/ interface Window : GlobalScope {
// the current browsing context
[LegacyUnforgeable, CrossOriginReadable] readonly attribute WindowProxy window;
@@ -148,6 +148,7 @@ partial interface Window {
partial interface Window {
// Shouldn't be public, but just to make things work for now
undefined webdriverCallback(optional any result);
+ undefined webdriverException(optional any result);
undefined webdriverTimeout();
};