mirror of
https://github.com/lexmount/moli.git
synced 2026-10-06 16:01:00 +00:00
fix(window): expose native closed accessors
This commit is contained in:
@@ -28,11 +28,11 @@ pub(super) use interceptors::{
|
||||
window_named_property_query,
|
||||
};
|
||||
pub(super) use surface::{
|
||||
window_custom_elements_getter, window_device_pixel_ratio_getter, window_frames_getter,
|
||||
window_inner_height_getter, window_inner_surface_height, window_inner_surface_width,
|
||||
window_inner_width_getter, window_navigator_getter, window_opener_getter,
|
||||
window_outer_height_getter, window_outer_width_getter, window_parent_getter,
|
||||
window_performance_getter, window_screen_getter, window_scroll_x_getter,
|
||||
window_closed_getter, window_custom_elements_getter, window_device_pixel_ratio_getter,
|
||||
window_frames_getter, window_inner_height_getter, window_inner_surface_height,
|
||||
window_inner_surface_width, window_inner_width_getter, window_navigator_getter,
|
||||
window_opener_getter, window_outer_height_getter, window_outer_width_getter,
|
||||
window_parent_getter, window_performance_getter, window_screen_getter, window_scroll_x_getter,
|
||||
window_scroll_y_getter, window_self_getter, window_speech_synthesis_getter, window_top_getter,
|
||||
window_visual_viewport_getter, window_window_getter,
|
||||
};
|
||||
|
||||
@@ -123,3 +123,27 @@ pub(crate) fn current_window_style_viewport(
|
||||
})
|
||||
.unwrap_or_else(|| host.style_viewport())
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap) fn window_has_discarded_child_browsing_context<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
receiver: v8::Local<'s, v8::Object>,
|
||||
) -> bool {
|
||||
let Some(handle) = window_child_context_handle(scope, receiver) else {
|
||||
return false;
|
||||
};
|
||||
let Some(host_ptr) = window_host_ptr(scope, receiver) else {
|
||||
return true;
|
||||
};
|
||||
let host = unsafe { &*host_ptr };
|
||||
// Container removal disconnects the DOM node before its unload callbacks.
|
||||
// The captured LocalWindow remains current until those callbacks finish;
|
||||
// checking its identity also keeps reattachment from reviving an old realm.
|
||||
let Some(context) = receiver.get_creation_context(scope) else {
|
||||
return true;
|
||||
};
|
||||
host.window_execution_context_identity_for_access_check(context)
|
||||
.is_none_or(|identity| {
|
||||
identity.dispatch_scope() != crate::native_bridge::OwnerDispatchScope::Child(handle)
|
||||
|| !host.window_execution_context_identity_is_current(identity)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::helpers::{
|
||||
window_child_context_handle, window_hidden_value, window_host_ptr, window_receiver,
|
||||
window_child_context_handle, window_has_discarded_child_browsing_context, window_hidden_value,
|
||||
window_host_ptr, window_receiver,
|
||||
};
|
||||
use super::*;
|
||||
|
||||
@@ -296,3 +297,21 @@ pub(in crate::context_bootstrap) fn window_self_getter<'s>(
|
||||
) {
|
||||
set_receiver_window_alias(scope, &args, WINDOW_SELF_SLOT, rv);
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap) fn window_closed_getter<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
args: v8::FunctionCallbackArguments<'s>,
|
||||
mut rv: v8::ReturnValue<'_, v8::Value>,
|
||||
) {
|
||||
let Some(receiver) = window_receiver(scope, &args) else {
|
||||
return;
|
||||
};
|
||||
if let Some(popup_id) = crate::native_bridge::lightweight_popup_id_from_window(scope, receiver)
|
||||
{
|
||||
let closed = window_host_ptr(scope, receiver)
|
||||
.is_none_or(|host_ptr| !unsafe { &*host_ptr }.lightweight_popup_is_open(popup_id));
|
||||
rv.set_bool(closed);
|
||||
return;
|
||||
}
|
||||
rv.set_bool(window_has_discarded_child_browsing_context(scope, receiver));
|
||||
}
|
||||
|
||||
@@ -190,6 +190,9 @@ struct WindowIdentityAccessorsDeclaration {
|
||||
#[webapi(accessor_property, getter = window_frames_getter)]
|
||||
frames: (),
|
||||
|
||||
#[webapi(accessor_property, getter = window_closed_getter)]
|
||||
closed: (),
|
||||
|
||||
#[webapi(accessor_property, getter = window_frame_element_getter)]
|
||||
frame_element: (),
|
||||
|
||||
|
||||
@@ -2069,3 +2069,62 @@ container.querySelector('a').click();
|
||||
|
||||
assert_eq!(result, "true|true|true");
|
||||
}
|
||||
#[test]
|
||||
fn window_closed_reflects_top_popup_and_popup_child_liveness() {
|
||||
let mut vm = new_storage_test_vm("https://window-closed.test/");
|
||||
|
||||
let result = vm
|
||||
.eval(
|
||||
r#"
|
||||
(() => {
|
||||
const popup = open();
|
||||
popup.document.body.appendChild(popup.document.createElement("iframe"));
|
||||
const child = popup[0];
|
||||
const descriptor = Object.getOwnPropertyDescriptor(window, "closed");
|
||||
const before = [window.closed, popup.closed, child.closed];
|
||||
popup.close();
|
||||
return JSON.stringify({
|
||||
descriptor: [
|
||||
descriptor.get.name,
|
||||
descriptor.get.length,
|
||||
typeof descriptor.set,
|
||||
descriptor.enumerable,
|
||||
descriptor.configurable
|
||||
],
|
||||
before,
|
||||
after: [
|
||||
popup.closed,
|
||||
child.closed,
|
||||
descriptor.get.call(popup),
|
||||
descriptor.get.call(child)
|
||||
]
|
||||
});
|
||||
})()
|
||||
"#,
|
||||
)
|
||||
.expect("Window.closed liveness probe should evaluate");
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
r#"{"descriptor":["get closed",0,"undefined",true,true],"before":[false,false,false],"after":[true,false,true,false]}"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn window_closed_reflects_removed_iframe_state() {
|
||||
let mut vm = new_parsed_test_vm("https://child-window-closed.test/", "<!doctype html><body>");
|
||||
let result = vm
|
||||
.eval(
|
||||
r#"(() => {
|
||||
const frame = document.body.appendChild(document.createElement('iframe'));
|
||||
const child = frame.contentWindow;
|
||||
const getter = Object.getOwnPropertyDescriptor(window, 'closed').get;
|
||||
const states = [child.closed, getter.call(child)];
|
||||
frame.remove();
|
||||
states.push(child.closed, getter.call(child));
|
||||
return JSON.stringify(states);
|
||||
})()"#,
|
||||
)
|
||||
.expect("closed should reflect iframe removal through the native getter");
|
||||
assert_eq!(result, "[false,false,true,true]");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user