CanGc fixes from eventtarget.rs (#33973)

Signed-off-by: taniishkaaa <tanishkasingh2004@gmail.com>
This commit is contained in:
tanishka 2024-10-23 04:13:52 +05:30 committed by GitHub
parent 7b392db02f
commit 7fbd2a521e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 108 additions and 81 deletions

View file

@ -55,7 +55,7 @@ DOMInterfaces = {
'BluetoothRemoteGATTServer': {
'inRealms': ['Connect'],
'canGc': ['GetPrimaryService', 'GetPrimaryServices', 'Connect'],
'canGc': ['GetPrimaryService', 'GetPrimaryServices', 'Connect', 'Disconnect'],
},
'BluetoothRemoteGATTService': {
@ -116,7 +116,7 @@ DOMInterfaces = {
},
'ElementInternals': {
'canGc': ['ReportValidity'],
'canGc': ['CheckValidity', 'ReportValidity'],
},
'EventSource': {
@ -184,11 +184,7 @@ DOMInterfaces = {
},
'HTMLButtonElement': {
'canGc': ['ReportValidity'],
},
'HTMLCanvasElement': {
'canGc': ['CaptureStream', 'GetContext'],
'canGc': ['CheckValidity', 'ReportValidity'],
},
'HTMLElement': {
@ -196,36 +192,40 @@ DOMInterfaces = {
},
'HTMLFieldSetElement': {
'canGc': ['ReportValidity'],
'canGc': ['CheckValidity', 'ReportValidity'],
},
'HTMLFormElement': {
'canGc': ['RequestSubmit', 'ReportValidity', 'Submit'],
},
'HTMLInputElement': {
'canGc': ['ReportValidity', 'SelectFiles'],
'canGc': ['CheckValidity', 'RequestSubmit', 'ReportValidity', 'Submit'],
},
'HTMLImageElement': {
'canGc': ['Width', 'Height', 'Decode'],
},
'HTMLInputElement': {
'canGc': ['CheckValidity', 'ReportValidity', 'SelectFiles'],
},
'HTMLMediaElement': {
'canGc': ['Load', 'Pause', 'Play', 'SetSrcObject'],
'inRealms': ['Play'],
},
'HTMLObjectElement': {
'canGc': ['ReportValidity'],
'canGc': ['CheckValidity', 'ReportValidity'],
},
'HTMLOutputElement': {
'canGc': ['ReportValidity'],
'canGc': ['CheckValidity', 'ReportValidity'],
},
'HTMLCanvasElement': {
'canGc': ['CaptureStream', 'GetContext'],
},
'HTMLSelectElement': {
'canGc': ['ReportValidity'],
'canGc': ['CheckValidity', 'ReportValidity'],
},
'HTMLTemplateElement': {
@ -233,7 +233,7 @@ DOMInterfaces = {
},
'HTMLTextAreaElement': {
'canGc': ['ReportValidity'],
'canGc': ['CheckValidity', 'ReportValidity'],
},
'Location': {
@ -295,6 +295,10 @@ DOMInterfaces = {
'canGc': ['Query', 'Request', 'Revoke'],
},
'Permissions': {
'canGc': ['Query', 'Request', 'Revoke'],
},
'Promise': {
'spiderMonkeyInterface': True,
},

View file

@ -110,7 +110,7 @@ struct BluetoothContext<T: AsyncBluetoothListener + DomObject> {
}
pub trait AsyncBluetoothListener {
fn handle_response(&self, result: BluetoothResponse, promise: &Rc<Promise>);
fn handle_response(&self, result: BluetoothResponse, promise: &Rc<Promise>, can_gc: CanGc);
}
impl<T> BluetoothContext<T>
@ -118,13 +118,16 @@ where
T: AsyncBluetoothListener + DomObject,
{
#[allow(crown::unrooted_must_root)]
fn response(&mut self, response: BluetoothResponseResult) {
fn response(&mut self, response: BluetoothResponseResult, can_gc: CanGc) {
let promise = self.promise.take().expect("bt promise is missing").root();
// JSAutoRealm needs to be manually made.
// Otherwise, Servo will crash.
match response {
Ok(response) => self.receiver.root().handle_response(response, &promise),
Ok(response) => self
.receiver
.root()
.handle_response(response, &promise, can_gc),
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
// Step 3 - 4.
Err(error) => promise.reject_error(Error::from(error)),
@ -259,7 +262,7 @@ pub fn response_async<T: AsyncBluetoothListener + DomObject + 'static>(
{
fn run_once(self) {
let mut context = self.context.lock().unwrap();
context.response(self.action);
context.response(self.action, CanGc::note());
}
}
@ -576,7 +579,7 @@ impl BluetoothMethods for Bluetooth {
}
impl AsyncBluetoothListener for Bluetooth {
fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>) {
fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>, _can_gc: CanGc) {
match response {
// https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
// Step 11, 13 - 14.
@ -753,6 +756,7 @@ impl PermissionAlgorithm for Bluetooth {
fn permission_revoke(
_descriptor: &BluetoothPermissionDescriptor,
status: &BluetoothPermissionResult,
can_gc: CanGc,
) {
// Step 1.
let global = status.global();
@ -775,7 +779,7 @@ impl PermissionAlgorithm for Bluetooth {
continue;
}
// Step 2.2 - 2.4
let _ = device.get_gatt().Disconnect();
let _ = device.get_gatt().Disconnect(can_gc);
}
}
}

View file

@ -193,7 +193,7 @@ impl BluetoothDevice {
// https://webbluetoothcg.github.io/web-bluetooth/#clean-up-the-disconnected-device
#[allow(crown::unrooted_must_root)]
pub fn clean_up_disconnected_device(&self) {
pub fn clean_up_disconnected_device(&self, can_gc: CanGc) {
// Step 1.
self.get_gatt().set_connected(false);
@ -224,7 +224,7 @@ impl BluetoothDevice {
// Step 8.
self.upcast::<EventTarget>()
.fire_bubbling_event(atom!("gattserverdisconnected"));
.fire_bubbling_event(atom!("gattserverdisconnected"), can_gc);
}
// https://webbluetoothcg.github.io/web-bluetooth/#garbage-collect-the-connection
@ -317,7 +317,7 @@ impl BluetoothDeviceMethods for BluetoothDevice {
}
impl AsyncBluetoothListener for BluetoothDevice {
fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>) {
fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>, _can_gc: CanGc) {
match response {
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-unwatchadvertisements
BluetoothResponse::WatchAdvertisements(_result) => {

View file

@ -25,6 +25,7 @@ use crate::dom::bluetoothdevice::BluetoothDevice;
use crate::dom::globalscope::GlobalScope;
use crate::dom::permissionstatus::PermissionStatus;
use crate::dom::promise::Promise;
use crate::script_runtime::CanGc;
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothpermissionresult
#[dom_struct]
@ -94,7 +95,7 @@ impl BluetoothPermissionResultMethods for BluetoothPermissionResult {
}
impl AsyncBluetoothListener for BluetoothPermissionResult {
fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>) {
fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>, _can_gc: CanGc) {
match response {
// https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
// Step 3, 11, 13 - 14.

View file

@ -298,7 +298,7 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
}
impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>) {
fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>, can_gc: CanGc) {
let device = self.Service().Device();
match response {
// https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
@ -328,7 +328,7 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
// Step 5.5.3.
self.upcast::<EventTarget>()
.fire_bubbling_event(atom!("characteristicvaluechanged"));
.fire_bubbling_event(atom!("characteristicvaluechanged"), can_gc);
// Step 5.5.4.
promise.resolve_native(&value);

View file

@ -179,7 +179,7 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
}
impl AsyncBluetoothListener for BluetoothRemoteGATTDescriptor {
fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>) {
fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>, _can_gc: CanGc) {
match response {
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue
BluetoothResponse::ReadValue(result) => {

View file

@ -95,7 +95,7 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-disconnect
fn Disconnect(&self) -> ErrorResult {
fn Disconnect(&self, can_gc: CanGc) -> ErrorResult {
// TODO: Step 1: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer.
// Step 2.
@ -104,7 +104,7 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
}
// Step 3.
self.Device().clean_up_disconnected_device();
self.Device().clean_up_disconnected_device(can_gc);
// Step 4 - 5:
self.Device().garbage_collect_the_connection()
@ -146,7 +146,7 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
}
impl AsyncBluetoothListener for BluetoothRemoteGATTServer {
fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>) {
fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>, _can_gc: CanGc) {
match response {
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect
BluetoothResponse::GATTServerConnect(connected) => {

View file

@ -163,7 +163,7 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
}
impl AsyncBluetoothListener for BluetoothRemoteGATTService {
fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>) {
fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>, _can_gc: CanGc) {
let device = self.Device();
match response {
// https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren

View file

@ -746,7 +746,7 @@ impl Document {
// Step 4.6.2 Set document's page showing flag to true.
document.page_showing.set(true);
// Step 4.6.3 Update the visibility state of document to "visible".
document.update_visibility_state(DocumentVisibilityState::Visible);
document.update_visibility_state(DocumentVisibilityState::Visible, CanGc::note());
// Step 4.6.4 Fire a page transition event named pageshow at document's relevant
// global object with true.
let event = PageTransitionEvent::new(
@ -2360,7 +2360,7 @@ impl Document {
.window
.dispatch_event_with_target_override(event, can_gc);
// Step 6 Update the visibility state of oldDocument to "hidden".
self.update_visibility_state(DocumentVisibilityState::Hidden);
self.update_visibility_state(DocumentVisibilityState::Hidden, can_gc);
}
// Step 7
if !self.fired_unload.get() {
@ -2721,7 +2721,7 @@ impl Document {
.queue(
task!(fire_dom_content_loaded_event: move || {
let document = document.root();
document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"));
document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"), CanGc::note());
update_with_current_instant(&document.dom_content_loaded_event_end);
}),
window.upcast(),
@ -4216,7 +4216,7 @@ impl Document {
}
/// <https://html.spec.whatwg.org/multipage/#visibility-state>
fn update_visibility_state(&self, visibility_state: DocumentVisibilityState) {
fn update_visibility_state(&self, visibility_state: DocumentVisibilityState, can_gc: CanGc) {
// Step 1 If document's visibility state equals visibilityState, then return.
if self.visibility_state.get() == visibility_state {
return;
@ -4255,7 +4255,7 @@ impl Document {
// Step 7 Fire an event named visibilitychange at document, with its bubbles attribute initialized to true.
self.upcast::<EventTarget>()
.fire_bubbling_event(atom!("visibilitychange"));
.fire_bubbling_event(atom!("visibilitychange"), can_gc);
}
}

View file

@ -317,11 +317,11 @@ impl ElementInternalsMethods for ElementInternals {
}
/// <https://html.spec.whatwg.org/multipage#dom-elementinternals-checkvalidity>
fn CheckValidity(&self) -> Fallible<bool> {
fn CheckValidity(&self, can_gc: CanGc) -> Fallible<bool> {
if !self.is_target_form_associated() {
return Err(Error::NotSupported);
}
Ok(self.check_validity())
Ok(self.check_validity(can_gc))
}
/// <https://html.spec.whatwg.org/multipage#dom-elementinternals-reportvalidity>

View file

@ -618,7 +618,7 @@ impl TaskOnce for EventTask {
let target = self.target.root();
let bubbles = self.bubbles;
let cancelable = self.cancelable;
target.fire_event_with_params(self.name, bubbles, cancelable);
target.fire_event_with_params(self.name, bubbles, cancelable, CanGc::note());
}
}

View file

@ -665,26 +665,38 @@ impl EventTarget {
name,
EventBubbles::DoesNotBubble,
EventCancelable::NotCancelable,
CanGc::note(),
)
}
// https://dom.spec.whatwg.org/#concept-event-fire
pub fn fire_bubbling_event(&self, name: Atom) -> DomRoot<Event> {
self.fire_event_with_params(name, EventBubbles::Bubbles, EventCancelable::NotCancelable)
pub fn fire_bubbling_event(&self, name: Atom, can_gc: CanGc) -> DomRoot<Event> {
self.fire_event_with_params(
name,
EventBubbles::Bubbles,
EventCancelable::NotCancelable,
can_gc,
)
}
// https://dom.spec.whatwg.org/#concept-event-fire
pub fn fire_cancelable_event(&self, name: Atom) -> DomRoot<Event> {
pub fn fire_cancelable_event(&self, name: Atom, can_gc: CanGc) -> DomRoot<Event> {
self.fire_event_with_params(
name,
EventBubbles::DoesNotBubble,
EventCancelable::Cancelable,
can_gc,
)
}
// https://dom.spec.whatwg.org/#concept-event-fire
pub fn fire_bubbling_cancelable_event(&self, name: Atom) -> DomRoot<Event> {
self.fire_event_with_params(name, EventBubbles::Bubbles, EventCancelable::Cancelable)
pub fn fire_bubbling_cancelable_event(&self, name: Atom, can_gc: CanGc) -> DomRoot<Event> {
self.fire_event_with_params(
name,
EventBubbles::Bubbles,
EventCancelable::Cancelable,
can_gc,
)
}
// https://dom.spec.whatwg.org/#concept-event-fire
@ -693,8 +705,9 @@ impl EventTarget {
name: Atom,
bubbles: EventBubbles,
cancelable: EventCancelable,
can_gc: CanGc,
) -> DomRoot<Event> {
let event = Event::new(&self.global(), name, bubbles, cancelable, CanGc::note());
let event = Event::new(&self.global(), name, bubbles, cancelable, can_gc);
event.fire(self);
event
}

View file

@ -170,8 +170,8 @@ impl HTMLButtonElementMethods for HTMLButtonElement {
}
// https://html.spec.whatwg.org/multipage/#dom-cva-checkvalidity
fn CheckValidity(&self) -> bool {
self.check_validity()
fn CheckValidity(&self, can_gc: CanGc) -> bool {
self.check_validity(can_gc)
}
// https://html.spec.whatwg.org/multipage/#dom-cva-reportvalidity

View file

@ -127,8 +127,8 @@ impl HTMLFieldSetElementMethods for HTMLFieldSetElement {
}
// https://html.spec.whatwg.org/multipage/#dom-cva-checkvalidity
fn CheckValidity(&self) -> bool {
self.check_validity()
fn CheckValidity(&self, can_gc: CanGc) -> bool {
self.check_validity(can_gc)
}
// https://html.spec.whatwg.org/multipage/#dom-cva-reportvalidity

View file

@ -629,8 +629,8 @@ impl HTMLFormElementMethods for HTMLFormElement {
}
/// <https://html.spec.whatwg.org/multipage/#dom-form-checkvalidity>
fn CheckValidity(&self) -> bool {
self.static_validation().is_ok()
fn CheckValidity(&self, can_gc: CanGc) -> bool {
self.static_validation(can_gc).is_ok()
}
/// <https://html.spec.whatwg.org/multipage/#dom-form-reportvalidity>
@ -1032,7 +1032,7 @@ impl HTMLFormElement {
/// <https://html.spec.whatwg.org/multipage/#interactively-validate-the-constraints>
fn interactive_validation(&self, can_gc: CanGc) -> Result<(), ()> {
// Step 1-2
let unhandled_invalid_controls = match self.static_validation() {
let unhandled_invalid_controls = match self.static_validation(can_gc) {
Ok(()) => return Ok(()),
Err(err) => err,
};
@ -1060,7 +1060,7 @@ impl HTMLFormElement {
/// Statitically validate the constraints of form elements
/// <https://html.spec.whatwg.org/multipage/#statically-validate-the-constraints>
fn static_validation(&self) -> Result<(), Vec<DomRoot<Element>>> {
fn static_validation(&self, can_gc: CanGc) -> Result<(), Vec<DomRoot<Element>>> {
let controls = self.controls.borrow();
// Step 1-3
let invalid_controls = controls
@ -1087,7 +1087,7 @@ impl HTMLFormElement {
.filter_map(|field| {
let event = field
.upcast::<EventTarget>()
.fire_cancelable_event(atom!("invalid"));
.fire_cancelable_event(atom!("invalid"), can_gc);
if !event.DefaultPrevented() {
return Some(field);
}
@ -1238,7 +1238,7 @@ impl HTMLFormElement {
let event = self
.upcast::<EventTarget>()
.fire_bubbling_cancelable_event(atom!("reset"));
.fire_bubbling_cancelable_event(atom!("reset"), CanGc::note());
if event.DefaultPrevented() {
return;
}

View file

@ -1586,8 +1586,8 @@ impl HTMLInputElementMethods for HTMLInputElement {
}
// https://html.spec.whatwg.org/multipage/#dom-cva-checkvalidity
fn CheckValidity(&self) -> bool {
self.check_validity()
fn CheckValidity(&self, can_gc: CanGc) -> bool {
self.check_validity(can_gc)
}
// https://html.spec.whatwg.org/multipage/#dom-cva-reportvalidity
@ -1889,8 +1889,8 @@ impl HTMLInputElement {
let filelist = FileList::new(&window, files);
self.filelist.set(Some(&filelist));
target.fire_bubbling_event(atom!("input"));
target.fire_bubbling_event(atom!("change"));
target.fire_bubbling_event(atom!("input"), can_gc);
target.fire_bubbling_event(atom!("change"), can_gc);
}
}
@ -2805,7 +2805,7 @@ impl Activatable for HTMLInputElement {
}
// https://html.spec.whatwg.org/multipage/#run-post-click-activation-steps
fn activation_behavior(&self, _event: &Event, _target: &EventTarget, _can_gc: CanGc) {
fn activation_behavior(&self, _event: &Event, _target: &EventTarget, can_gc: CanGc) {
let ty = self.input_type();
match ty {
InputType::Submit => {
@ -2836,8 +2836,8 @@ impl Activatable for HTMLInputElement {
return;
}
let target = self.upcast::<EventTarget>();
target.fire_bubbling_event(atom!("input"));
target.fire_bubbling_event(atom!("change"));
target.fire_bubbling_event(atom!("input"), can_gc);
target.fire_bubbling_event(atom!("change"), can_gc);
},
InputType::File => self.select_files(None, CanGc::note()),
_ => (),

View file

@ -110,8 +110,8 @@ impl HTMLObjectElementMethods for HTMLObjectElement {
}
// https://html.spec.whatwg.org/multipage/#dom-cva-checkvalidity
fn CheckValidity(&self) -> bool {
self.check_validity()
fn CheckValidity(&self, can_gc: CanGc) -> bool {
self.check_validity(can_gc)
}
// https://html.spec.whatwg.org/multipage/#dom-cva-reportvalidity

View file

@ -132,8 +132,8 @@ impl HTMLOutputElementMethods for HTMLOutputElement {
}
// https://html.spec.whatwg.org/multipage/#dom-cva-checkvalidity
fn CheckValidity(&self) -> bool {
self.check_validity()
fn CheckValidity(&self, can_gc: CanGc) -> bool {
self.check_validity(can_gc)
}
// https://html.spec.whatwg.org/multipage/#dom-cva-reportvalidity

View file

@ -391,8 +391,8 @@ impl HTMLSelectElementMethods for HTMLSelectElement {
}
// https://html.spec.whatwg.org/multipage/#dom-cva-checkvalidity
fn CheckValidity(&self) -> bool {
self.check_validity()
fn CheckValidity(&self, can_gc: CanGc) -> bool {
self.check_validity(can_gc)
}
// https://html.spec.whatwg.org/multipage/#dom-cva-reportvalidity

View file

@ -424,8 +424,8 @@ impl HTMLTextAreaElementMethods for HTMLTextAreaElement {
}
// https://html.spec.whatwg.org/multipage/#dom-cva-checkvalidity
fn CheckValidity(&self) -> bool {
self.check_validity()
fn CheckValidity(&self, can_gc: CanGc) -> bool {
self.check_validity(can_gc)
}
// https://html.spec.whatwg.org/multipage/#dom-cva-reportvalidity

View file

@ -46,7 +46,7 @@ pub trait PermissionAlgorithm {
descriptor: &Self::Descriptor,
status: &Self::Status,
);
fn permission_revoke(descriptor: &Self::Descriptor, status: &Self::Status);
fn permission_revoke(descriptor: &Self::Descriptor, status: &Self::Status, can_gc: CanGc);
}
enum Operation {
@ -139,7 +139,7 @@ impl Permissions {
.remove(&root_desc.name.to_string());
// (Revoke) Step 4.
Bluetooth::permission_revoke(&bluetooth_desc, &result)
Bluetooth::permission_revoke(&bluetooth_desc, &result, can_gc)
},
}
},
@ -171,7 +171,7 @@ impl Permissions {
.remove(&root_desc.name.to_string());
// (Revoke) Step 4.
Permissions::permission_revoke(&root_desc, &status);
Permissions::permission_revoke(&root_desc, &status, can_gc);
},
}
},
@ -270,7 +270,12 @@ impl PermissionAlgorithm for Permissions {
Permissions::permission_query(cx, promise, descriptor, status);
}
fn permission_revoke(_descriptor: &PermissionDescriptor, _status: &PermissionStatus) {}
fn permission_revoke(
_descriptor: &PermissionDescriptor,
_status: &PermissionStatus,
_can_gc: CanGc,
) {
}
}
// https://w3c.github.io/permissions/#permission-state

View file

@ -35,11 +35,11 @@ pub trait Validatable {
}
/// <https://html.spec.whatwg.org/multipage/#check-validity-steps>
fn check_validity(&self) -> bool {
fn check_validity(&self, can_gc: CanGc) -> bool {
if self.is_instance_validatable() && !self.satisfies_constraints() {
self.as_element()
.upcast::<EventTarget>()
.fire_cancelable_event(atom!("invalid"));
.fire_cancelable_event(atom!("invalid"), can_gc);
false
} else {
true
@ -61,7 +61,7 @@ pub trait Validatable {
let event = self
.as_element()
.upcast::<EventTarget>()
.fire_cancelable_event(atom!("invalid"));
.fire_cancelable_event(atom!("invalid"), can_gc);
// Step 1.2.
if !event.DefaultPrevented() {

View file

@ -324,7 +324,7 @@ impl XRSystem {
let xr = xr.root();
let interacting = ScriptThread::is_user_interacting();
ScriptThread::set_user_interacting(true);
xr.upcast::<EventTarget>().fire_bubbling_event(atom!("sessionavailable"));
xr.upcast::<EventTarget>().fire_bubbling_event(atom!("sessionavailable"), CanGc::note());
ScriptThread::set_user_interacting(interacting);
}),
window.upcast(),