1
0
Fork 0
mirror of https://github.com/servo/servo.git synced 2025-09-22 21:00:14 +01:00
servo/components/script/dom/bindings/reflector.rs
Josh Matthews 3a04f4195e
script: Return global objects for DOM objects in the relevant realm ()
DomObject::global is a tricky API because it's used pervasively but has
subtle requirements that are not documented and not yet enforced by the
type system (). The method returns the relevant global object for
a given DOM object, but that operation is only meaningful if there is an
active realm. We usually, but not always, have an active realm.

This change avoids a footgun by following the principle of least
surprise. Rather than making every single caller of `something.global()`
both prove that there is an active realm and think about which realm
they want active, we implement the obvious behaviour: always activate
the realm of the callee before obtaining the relevant global.
 
Testing: Existing WPT coverage is sufficient; this method is called all
over the codebase.
Fixes:  

Signed-off-by: Josh Matthews <josh@joshmatthews.net>
2025-05-25 03:21:05 +00:00

68 lines
2.4 KiB
Rust

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! The `Reflector` struct.
use js::rust::HandleObject;
use script_bindings::interfaces::GlobalScopeHelpers;
use crate::DomTypes;
use crate::dom::bindings::conversions::DerivedFrom;
use crate::dom::bindings::root::DomRoot;
use crate::dom::globalscope::GlobalScope;
use crate::realms::{InRealm, enter_realm};
use crate::script_runtime::CanGc;
/// Create the reflector for a new DOM object and yield ownership to the
/// reflector.
pub(crate) fn reflect_dom_object<D, T, U>(obj: Box<T>, global: &U, can_gc: CanGc) -> DomRoot<T>
where
D: DomTypes,
T: DomObject + DomObjectWrap<D>,
U: DerivedFrom<D::GlobalScope>,
{
let global_scope = global.upcast();
unsafe { T::WRAP(D::GlobalScope::get_cx(), global_scope, None, obj, can_gc) }
}
pub(crate) fn reflect_dom_object_with_proto<D, T, U>(
obj: Box<T>,
global: &U,
proto: Option<HandleObject>,
can_gc: CanGc,
) -> DomRoot<T>
where
D: DomTypes,
T: DomObject + DomObjectWrap<D>,
U: DerivedFrom<D::GlobalScope>,
{
let global_scope = global.upcast();
unsafe { T::WRAP(D::GlobalScope::get_cx(), global_scope, proto, obj, can_gc) }
}
pub(crate) trait DomGlobal {
/// Returns the [relevant global] in whatever realm is currently active.
///
/// [relevant global]: https://html.spec.whatwg.org/multipage/#concept-relevant-global
fn global_(&self, realm: InRealm) -> DomRoot<GlobalScope>;
/// Returns the [relevant global] in the same realm as the callee object.
/// If you know the callee's realm is already the current realm, it is
/// more efficient to call [DomGlobal::global_] instead.
///
/// [relevant global]: https://html.spec.whatwg.org/multipage/#concept-relevant-global
fn global(&self) -> DomRoot<GlobalScope>;
}
impl<T: DomGlobalGeneric<crate::DomTypeHolder>> DomGlobal for T {
fn global_(&self, realm: InRealm) -> DomRoot<GlobalScope> {
<Self as DomGlobalGeneric<crate::DomTypeHolder>>::global_(self, realm)
}
fn global(&self) -> DomRoot<GlobalScope> {
let realm = enter_realm(self);
<Self as DomGlobalGeneric<crate::DomTypeHolder>>::global_(self, InRealm::entered(&realm))
}
}
pub(crate) use script_bindings::reflector::*;