script/dom/geolocation/
geolocation.rs1use std::cell::{Cell, RefCell};
5
6use dom_struct::dom_struct;
7use js::context::JSContext;
8use rustc_hash::FxHashSet;
9use script_bindings::callback::{ExceptionHandling, OwnerWindow, RootedCallback};
10use script_bindings::codegen::GenericBindings::GeolocationBinding::Geolocation_Binding::GeolocationMethods;
11use script_bindings::codegen::GenericBindings::GeolocationBinding::{
12 PositionCallback, PositionErrorCallback, PositionOptions,
13};
14use script_bindings::codegen::GenericBindings::PermissionStatusBinding::PermissionName;
15use script_bindings::codegen::GenericBindings::WindowBinding::WindowMethods;
16use script_bindings::domstring::DOMString;
17use script_bindings::reflector::{Reflector, reflect_dom_object};
18use script_bindings::root::DomRoot;
19
20use crate::dom::bindings::codegen::DomTypeHolder::DomTypeHolder;
21use crate::dom::bindings::reflector::DomGlobal;
22use crate::dom::geolocationpositionerror::GeolocationPositionError;
23use crate::dom::globalscope::GlobalScope;
24
25#[dom_struct]
26pub struct Geolocation {
27 reflector_: Reflector,
28 watch_ids: RefCell<FxHashSet<u32>>,
30 next_watch_id: Cell<u32>,
31}
32
33impl Geolocation {
34 fn new_inherited() -> Self {
35 Geolocation {
36 reflector_: Reflector::new(),
37 watch_ids: RefCell::new(FxHashSet::default()),
38 next_watch_id: Cell::new(1),
39 }
40 }
41
42 pub(crate) fn new(cx: &mut JSContext, global: &GlobalScope) -> DomRoot<Self> {
43 reflect_dom_object(cx, Box::new(Self::new_inherited()), global)
44 }
45
46 fn request_position(
48 &self,
49 cx: &mut JSContext,
50 _success_callback: RootedCallback<PositionCallback<DomTypeHolder>>,
51 error_callback: Option<RootedCallback<PositionErrorCallback<DomTypeHolder>>>,
52 _options: &PositionOptions,
53 watch_id: Option<u32>,
54 ) {
55 let document = self.global().as_window().Document();
58 if !document.allowed_to_use_feature(PermissionName::Geolocation) {
60 if let Some(id) = watch_id {
61 self.watch_ids.borrow_mut().remove(&id);
63 }
64 if let Some(error_callback) = error_callback {
66 let position_error = GeolocationPositionError::permission_denied(
67 cx,
68 &self.global(),
69 DOMString::from_static("User denied Geolocation"),
70 );
71 let _ = error_callback.Call_(cx, self, &position_error, ExceptionHandling::Report);
72 }
73 return;
75 }
76 if !self.global().is_secure_context() {
78 if let Some(id) = watch_id {
79 self.watch_ids.borrow_mut().remove(&id);
81 }
82 if let Some(error_callback) = error_callback {
84 let position_error = GeolocationPositionError::permission_denied(
85 cx,
86 &self.global(),
87 DOMString::from_static("Insecure context for Geolocation"),
88 );
89 let _ = error_callback.Call_(cx, self, &position_error, ExceptionHandling::Report);
90 }
91 #[expect(clippy::needless_return)]
93 return;
94 }
95 }
98}
99
100impl GeolocationMethods<DomTypeHolder> for Geolocation {
101 fn GetCurrentPosition(
103 &self,
104 cx: &mut JSContext,
105 success_callback: RootedCallback<PositionCallback<DomTypeHolder>>,
106 error_callback: Option<RootedCallback<PositionErrorCallback<DomTypeHolder>>>,
107 options: &PositionOptions,
108 ) {
109 if !self.global().as_window().Document().is_fully_active() {
111 if let Some(error_callback) = error_callback {
113 let position_error = GeolocationPositionError::position_unavailable(
114 cx,
115 &self.global(),
116 DOMString::from_static("Document is not fully active"),
117 );
118 let _ = error_callback.Call_(cx, self, &position_error, ExceptionHandling::Report);
119 }
120 return;
122 }
123 self.request_position(cx, success_callback, error_callback, options, None)
125 }
126
127 fn WatchPosition(
129 &self,
130 cx: &mut JSContext,
131 success_callback: RootedCallback<PositionCallback<DomTypeHolder>>,
132 error_callback: Option<RootedCallback<PositionErrorCallback<DomTypeHolder>>>,
133 options: &PositionOptions,
134 ) -> i32 {
135 if !self.global().as_window().Document().is_fully_active() {
137 if let Some(error_callback) = error_callback {
139 let position_error = GeolocationPositionError::position_unavailable(
140 cx,
141 &self.global(),
142 DOMString::from_static("Document is not fully active"),
143 );
144 let _ = error_callback.Call_(cx, self, &position_error, ExceptionHandling::Report);
145 }
146 return 0;
148 }
149 let watch_id = self.next_watch_id.get();
151 self.next_watch_id.set(watch_id + 1);
152 self.watch_ids.borrow_mut().insert(watch_id);
154 self.request_position(
156 cx,
157 success_callback,
158 error_callback,
159 options,
160 Some(watch_id),
161 );
162 watch_id as i32
164 }
165
166 fn ClearWatch(&self, watch_id: i32) {
168 let watch_id = u32::try_from(watch_id).ok();
169 if let Some(id) = watch_id {
170 self.watch_ids.borrow_mut().remove(&id);
171 }
172 }
173}
174
175impl OwnerWindow<crate::DomTypeHolder> for Geolocation {}