/
githubmirror
/
servo
Обзор
Документация
Войти
/
githubmirror
/
servo
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
components/script/dom/geolocation/geolocation.rs
203 строки
8 KB
Josh Matthews
script: Ensure event handlers on adopted elements check the owner document. (#46596)
18 июл 2026, 07:29
Не верифицирован
18 июл 2026, 07:29
1c68dd1
Код
Авторство
О чём код?
/* 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/. */ use std::cell::{Cell, RefCell}; use std::rc::Rc; use dom_struct::dom_struct; use js::context::JSContext; use js::gc::HandleValue; use js::jsapi::IsCallable; use rustc_hash::FxHashSet; use script_bindings::callback::{ExceptionHandling, OwnerWindow}; use script_bindings::codegen::GenericBindings::GeolocationBinding::Geolocation_Binding::GeolocationMethods; use script_bindings::codegen::GenericBindings::GeolocationBinding::{ PositionCallback, PositionErrorCallback, PositionOptions, }; use script_bindings::codegen::GenericBindings::PermissionStatusBinding::PermissionName; use script_bindings::codegen::GenericBindings::WindowBinding::WindowMethods; use script_bindings::domstring::DOMString; use script_bindings::error::{Error, Fallible}; use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx}; use script_bindings::root::DomRoot; use crate::dom::bindings::codegen::DomTypeHolder::DomTypeHolder; use crate::dom::bindings::reflector::DomGlobal; use crate::dom::geolocationpositionerror::GeolocationPositionError; use crate::dom::globalscope::GlobalScope; fn cast_error_callback( cx: &mut JSContext, error_callback: HandleValue, ) -> Fallible<Option<Rc<PositionErrorCallback<DomTypeHolder>>>> { if error_callback.get().is_object() { let error_callback = error_callback.to_object(); #[expect(unsafe_code)] unsafe { if IsCallable(error_callback) { Ok(Some(PositionErrorCallback::new(cx, error_callback))) } else { Err(Error::Type(c"Value is not callable.".to_owned())) } } } else if error_callback.get().is_null_or_undefined() { Ok(None) } else { Err(Error::Type(c"Value is not an object.".to_owned())) } } #[dom_struct] pub struct Geolocation { reflector_: Reflector, /// <https://www.w3.org/TR/geolocation/#dfn-watchids> watch_ids: RefCell<FxHashSet<u32>>, next_watch_id: Cell<u32>, } impl Geolocation { fn new_inherited() -> Self { Geolocation { reflector_: Reflector::new(), watch_ids: RefCell::new(FxHashSet::default()), next_watch_id: Cell::new(1), } } pub(crate) fn new(cx: &mut JSContext, global: &GlobalScope) -> DomRoot<Self> { reflect_dom_object_with_cx(Box::new(Self::new_inherited()), global, cx) } /// <https://www.w3.org/TR/geolocation/#dfn-request-a-position> fn request_position( &self, cx: &mut JSContext, _success_callback: Rc<PositionCallback<DomTypeHolder>>, error_callback: Option<Rc<PositionErrorCallback<DomTypeHolder>>>, _options: &PositionOptions, watch_id: Option<u32>, ) -> Fallible<()> { // Step 1. Let watchIDs be geolocation's [[watchIDs]]. // Step 2. Let document be the geolocation's relevant global object's associated Document. let document = self.global().as_window().Document(); // Step 3. If document is not allowed to use the "geolocation" feature: if !document.allowed_to_use_feature(PermissionName::Geolocation) { if let Some(id) = watch_id { // Step 3.1 If watchId was passed, remove watchId from watchIDs. self.watch_ids.borrow_mut().remove(&id); } // Step 3.2. Call back with error passing errorCallback and PERMISSION_DENIED. if let Some(error_callback) = error_callback { let position_error = GeolocationPositionError::permission_denied( cx, &self.global(), DOMString::from("User denied Geolocation".to_string()), ); error_callback.Call_(cx, self, &position_error, ExceptionHandling::Report)?; } // Step 3.3 Terminate this algorithm. return Ok(()); } // Step 4. If geolocation's environment settings object is a non-secure context: if !self.global().is_secure_context() { if let Some(id) = watch_id { // Step 4.1 If watchId was passed, remove watchId from watchIDs. self.watch_ids.borrow_mut().remove(&id); } // Step 4.2. Call back with error passing errorCallback and PERMISSION_DENIED. if let Some(error_callback) = error_callback { let position_error = GeolocationPositionError::permission_denied( cx, &self.global(), DOMString::from("Insecure context for Geolocation".to_string()), ); error_callback.Call_(cx, self, &position_error, ExceptionHandling::Report)?; } // Step 4.3 Terminate this algorithm. return Ok(()); } // TODO: Step 5 // TODO: Step 6. Let descriptor be a new PermissionDescriptor whose name is "geolocation". Ok(()) } } impl GeolocationMethods<DomTypeHolder> for Geolocation { /// <https://www.w3.org/TR/geolocation/#dom-geolocation-getcurrentposition> fn GetCurrentPosition( &self, cx: &mut JSContext, success_callback: Rc<PositionCallback<DomTypeHolder>>, error_callback: HandleValue, options: &PositionOptions, ) -> Fallible<()> { let error_callback = cast_error_callback(cx, error_callback)?; // Step 1. If this's relevant global object's associated Document is not fully active: if !self.global().as_window().Document().is_active() { // Step 1.1 Call back with error errorCallback and POSITION_UNAVAILABLE. if let Some(error_callback) = error_callback { let position_error = GeolocationPositionError::position_unavailable( cx, &self.global(), DOMString::from("Document is not fully active".to_string()), ); error_callback.Call_(cx, self, &position_error, ExceptionHandling::Report)?; } // Step 1.2 Terminate this algorithm. return Ok(()); } // Step 2. Request a position passing this, successCallback, errorCallback, and options. self.request_position(cx, success_callback, error_callback, options, None) } /// <https://www.w3.org/TR/geolocation/#watchposition-method> fn WatchPosition( &self, cx: &mut JSContext, success_callback: Rc<PositionCallback<DomTypeHolder>>, error_callback: HandleValue, options: &PositionOptions, ) -> Fallible<i32> { let error_callback = cast_error_callback(cx, error_callback)?; // Step 1. If this's relevant global object's associated Document is not fully active: if !self.global().as_window().Document().is_active() { // Step 1.1 Call back with error errorCallback and POSITION_UNAVAILABLE. if let Some(error_callback) = error_callback { let position_error = GeolocationPositionError::position_unavailable( cx, &self.global(), DOMString::from("Document is not fully active".to_string()), ); error_callback.Call_(cx, self, &position_error, ExceptionHandling::Report)?; } // Step 1.2 Return 0. return Ok(0); } // Step 2. Let watchId be an implementation-defined unsigned long that is greater than zero. let watch_id = self.next_watch_id.get(); self.next_watch_id.set(watch_id + 1); // Step 3. Append watchId to this's [[watchIDs]]. self.watch_ids.borrow_mut().insert(watch_id); // Step 4. Request a position passing this, successCallback, errorCallback, options, and watchId. self.request_position( cx, success_callback, error_callback, options, Some(watch_id), )?; // Step 5. Return watchId. Ok(watch_id as i32) } /// <https://www.w3.org/TR/geolocation/#clearwatch-method> fn ClearWatch(&self, watch_id: i32) { let watch_id = u32::try_from(watch_id).ok(); if let Some(id) = watch_id { self.watch_ids.borrow_mut().remove(&id); } } } impl OwnerWindow<crate::DomTypeHolder> for Geolocation {}