ladybird/Libraries/LibWeb/WebXR/XRSession.cpp

148 lines
5.3 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2025, Psychpsyo <psychpsyo@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/Realm.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Bindings/XRSessionPrototype.h>
#include <LibWeb/HTML/EventNames.h>
#include <LibWeb/HTML/Scripting/Environments.h>
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
#include <LibWeb/WebIDL/Promise.h>
#include <LibWeb/WebXR/XRSession.h>
#include <LibWeb/WebXR/XRSessionEvent.h>
#include <LibWeb/WebXR/XRSystem.h>
namespace Web::WebXR {
GC_DEFINE_ALLOCATOR(XRSession);
GC::Ref<XRSession> XRSession::create(JS::Realm& realm, GC::Ref<XRSystem> xr_system)
{
return realm.create<XRSession>(realm, xr_system);
}
XRSession::XRSession(JS::Realm& realm, XRSystem& xr_system)
: DOM::EventTarget(realm)
, m_xr_system(xr_system)
{
}
void XRSession::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(XRSession);
Base::initialize(realm);
}
void XRSession::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_xr_system);
visitor.visit(m_outstanding_promises);
}
GC::Ref<WebIDL::Promise> XRSession::create_promise(JS::Realm& realm)
{
auto promise = WebIDL::create_promise(realm);
m_outstanding_promises.append(promise);
return promise;
}
void XRSession::resolve_promise(JS::Realm& realm, WebIDL::Promise const& promise, JS::Value value)
{
WebIDL::resolve_promise(realm, promise, value);
m_outstanding_promises.remove_first_matching([&](auto& entry) { return entry == &promise; });
}
void XRSession::reject_promise(JS::Realm& realm, WebIDL::Promise const& promise, JS::Value value)
{
WebIDL::reject_promise(realm, promise, value);
m_outstanding_promises.remove_first_matching([&](auto& entry) { return entry == &promise; });
}
// https://immersive-web.github.io/webxr/#dom-xrsession-updaterenderstate
void XRSession::update_render_state(XRRenderStateInit const&)
{
dbgln("FIXME: stubbed out XRSession.updateRenderState()");
}
GC::Ref<WebIDL::Promise> XRSession::end()
{
// 1. Let promise be a new Promise in the relevant realm of this XRSession.
auto& realm = HTML::relevant_realm(*this);
auto promise = WebIDL::create_promise(realm);
// 2. If the ended value of this is true, reject promise with a "InvalidStateError" DOMException and return promise.
if (m_ended)
WebIDL::reject_promise(realm, promise, WebIDL::InvalidStateError::create(realm, "Session already ended."_utf16));
// 3. Shut down this.
shut_down();
// 4. Queue a task to perform the following steps:
HTML::queue_a_task(HTML::Task::Source::Unspecified, nullptr, nullptr, GC::create_function(realm.heap(), [&realm, promise]() {
// 1. Wait until any platform-specific steps related to shutting down the session have completed.
// FIXME: Do this once we have any.
// 2. Resolve promise.
HTML::TemporaryExecutionContext context { realm, HTML::TemporaryExecutionContext::CallbacksEnabled::Yes };
WebIDL::resolve_promise(realm, promise);
}));
// 5. Return promise.
return promise;
}
// https://immersive-web.github.io/webxr/#shut-down-the-session
void XRSession::shut_down()
{
auto& realm = HTML::relevant_realm(*this);
// 1. Set sessions ended value to true.
m_ended = true;
// 2. If the active immersive session is equal to session, set the active immersive session to null.
if (m_xr_system->active_immersive_session() == this)
m_xr_system->set_active_immersive_session({});
// 3. Remove session from the list of inline sessions.
m_xr_system->remove_inline_session(*this);
// 4. Reject any outstanding promises returned by session with an InvalidStateError, except for any promises returned by end().
for (auto promise : m_outstanding_promises) {
WebIDL::reject_promise(realm, promise, WebIDL::InvalidStateError::create(realm, "Session ended."_utf16));
}
m_outstanding_promises.clear();
// 5. If no other features of the user agent are actively using them, perform the necessary platform-specific steps to shut down the devices tracking and rendering capabilities. This MUST include:
// - Releasing exclusive access to the XR device if session is an immersive session.
// - Deallocating any graphics resources acquired by session for presentation to the XR device.
// - Putting the XR device in a state such that a different source may be able to initiate a session with the same device if session is an immersive session.
// FIXME: Implement this once we have any of this.
// 6. Queue a task that fires an XRSessionEvent named end on session.
HTML::queue_a_task(HTML::Task::Source::Unspecified, nullptr, nullptr, GC::create_function(realm.heap(), [this, &realm]() {
XRSessionEventInit init;
init.session = this;
auto event = XRSessionEvent::create(realm, HTML::EventNames::end, init);
this->dispatch_event(event);
}));
}
// https://immersive-web.github.io/webxr/#dom-xrsession-onend
GC::Ptr<WebIDL::CallbackType> XRSession::onend()
{
return event_handler_attribute(HTML::EventNames::end);
}
// https://www.w3.org/TR/web-animations-1/#dom-animation-onfinish
void XRSession::set_onend(GC::Ptr<WebIDL::CallbackType> event_handler)
{
set_event_handler_attribute(HTML::EventNames::end, event_handler);
}
}