feat(media): expose the MediaSession interface object

This commit is contained in:
ldm0
2026-10-02 15:14:20 +08:00
parent c1893e0599
commit b3933d8117
4 changed files with 50 additions and 0 deletions
@@ -560,6 +560,10 @@ const CONSTRUCTOR_SPECS_BEFORE_STREAMS: &[ConstructorSpec] = &[
interface: web_api_interfaces::ClipboardItem::DESCRIPTOR,
kind: ConstructorKind::ClipboardItem,
},
ConstructorSpec {
interface: web_api_interfaces::MediaSession::DESCRIPTOR,
kind: ConstructorKind::Illegal,
},
ConstructorSpec {
interface: web_api_interfaces::MediaCapabilities::DESCRIPTOR,
kind: ConstructorKind::Illegal,
@@ -0,0 +1,44 @@
use super::*;
#[test]
fn media_session_interfaces_preserve_native_inheritance_and_realm_contracts() {
for url in [
"https://media-session-interfaces.test/",
"http://media-session-interfaces.test/",
"http://localhost/",
] {
let mut vm = new_storage_page_task_executor_test_vm(url);
vm.eval("document.body.innerHTML = '<iframe id=child></iframe>'")
.unwrap();
assert_eq!(vm.eval(r#"(() => {
const assert = (ok, message) => { if (!ok) throw Error(message); };
{
const realms = [window, document.getElementById('child').contentWindow];
for (const w of realms) {
for (const [name, parentName] of [["MediaSession","Object"]]) {
if (false && !w.isSecureContext) {
assert(!(name in w), name + ' hidden in an insecure realm');
continue;
}
const C = w[name], parent = w[parentName];
assert(typeof C === 'function' && C.name === name && C.length === 0, name + ' interface object');
const descriptor = Object.getOwnPropertyDescriptor(w, name);
assert(descriptor.writable && descriptor.configurable && !descriptor.enumerable, name + ' global descriptor');
assert(Object.getPrototypeOf(C.prototype) === parent.prototype, name + ' prototype inheritance');
assert(Object.getPrototypeOf(C) === (parentName === 'Object' ? w.Function.prototype : parent), name + ' interface inheritance');
assert(C.prototype.constructor === C, name + ' prototype constructor');
const tag = Object.getOwnPropertyDescriptor(C.prototype, Symbol.toStringTag);
assert(tag.value === name && !tag.writable && !tag.enumerable && tag.configurable, name + ' tag');
for (const call of [() => C(), () => new C()]) {
let error;
try { call(); } catch (caught) { error = caught; }
assert(error instanceof w.TypeError, name + ' rejects direct construction in the callee realm');
if (w !== window) assert(!(error instanceof TypeError), name + ' foreign error realm');
}
}
}
return true;
}
})()"#).unwrap(), "true", "{url}");
}
}
@@ -2183,3 +2183,4 @@ mod intersection_target_order;
mod observer_element_arguments;
mod media_device_interfaces;
mod media_session_interfaces;
@@ -294,6 +294,7 @@ interfaces! {
MediaList;
MediaQueryList: EventTarget;
MediaQueryListEvent: Event;
MediaSession;
MediaSource: EventTarget;
MemoryInfo;
MessageChannel;