1use js::rust::HandleObject;
8use servo_config::prefs::get;
9
10use crate::DomTypes;
11use crate::codegen::Globals::Globals;
12use crate::interface::is_exposed_in;
13use crate::interfaces::GlobalScopeHelpers;
14use crate::realms::{AlreadyInRealm, InRealm};
15use crate::script_runtime::JSContext;
16
17pub(crate) struct Guard<T: Clone + Copy> {
19 conditions: &'static [Condition],
20 value: T,
21}
22
23impl<T: Clone + Copy> Guard<T> {
24 pub(crate) const fn new(conditions: &'static [Condition], value: T) -> Self {
26 Guard { conditions, value }
27 }
28
29 pub(crate) fn expose<D: DomTypes>(
33 &self,
34 cx: JSContext,
35 obj: HandleObject,
36 global: HandleObject,
37 ) -> Option<T> {
38 let mut exposed_on_global = false;
39 let conditions_satisfied = self.conditions.iter().all(|c| match c {
40 Condition::Satisfied => {
41 exposed_on_global = true;
42 true
43 },
44 Condition::Exposed(globals) => {
46 exposed_on_global |= is_exposed_in(global, *globals);
47 true
48 },
49 _ => c.is_satisfied::<D>(cx, obj, global),
50 });
51
52 if conditions_satisfied && exposed_on_global {
53 Some(self.value)
54 } else {
55 None
56 }
57 }
58}
59
60#[derive(Clone, Copy)]
62pub(crate) enum Condition {
63 Func(fn(JSContext, HandleObject) -> bool),
65 Pref(&'static str),
67 Exposed(Globals),
69 SecureContext(),
70 Satisfied,
72}
73
74fn is_secure_context<D: DomTypes>(cx: JSContext) -> bool {
75 unsafe {
76 let in_realm_proof = AlreadyInRealm::assert_for_cx(JSContext::from_ptr(*cx));
77 D::GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof)).is_secure_context()
78 }
79}
80
81impl Condition {
82 pub(crate) fn is_satisfied<D: DomTypes>(
83 &self,
84 cx: JSContext,
85 obj: HandleObject,
86 global: HandleObject,
87 ) -> bool {
88 match *self {
89 Condition::Pref(name) => get().get_value(name).try_into().unwrap_or(false),
90 Condition::Func(f) => f(cx, obj),
91 Condition::Exposed(globals) => is_exposed_in(global, globals),
92 Condition::SecureContext() => is_secure_context::<D>(cx),
93 Condition::Satisfied => true,
94 }
95 }
96}