diff options
Diffstat (limited to 'components/script/dom/window.rs')
-rw-r--r-- | components/script/dom/window.rs | 137 |
1 files changed, 131 insertions, 6 deletions
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index a685bbb25f2..b115add8611 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -32,8 +32,9 @@ use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarker use dom_struct::dom_struct; use embedder_traits::user_content_manager::{UserContentManager, UserScript}; use embedder_traits::{ - AlertResponse, ConfirmResponse, EmbedderMsg, PromptResponse, SimpleDialog, Theme, - ViewportDetails, WebDriverJSError, WebDriverJSResult, + AlertResponse, ConfirmResponse, EmbedderMsg, GamepadEvent, GamepadSupportedHapticEffects, + GamepadUpdateType, PromptResponse, SimpleDialog, Theme, ViewportDetails, WebDriverJSError, + WebDriverJSResult, }; use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect}; use euclid::{Point2D, Rect, Scale, Size2D, Vector2D}; @@ -61,6 +62,8 @@ use num_traits::ToPrimitive; use profile_traits::ipc as ProfiledIpc; use profile_traits::mem::ProfilerChan as MemProfilerChan; use profile_traits::time::ProfilerChan as TimeProfilerChan; +use script_bindings::codegen::GenericBindings::NavigatorBinding::NavigatorMethods; +use script_bindings::codegen::GenericBindings::PerformanceBinding::PerformanceMethods; use script_bindings::interfaces::WindowHelpers; use script_layout_interface::{ FragmentType, Layout, PendingImageState, QueryMsg, Reflow, ReflowGoal, ReflowRequest, @@ -125,6 +128,8 @@ use crate::dom::document::{AnimationFrameCallback, Document, ReflowTriggerCondit use crate::dom::element::Element; use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus}; use crate::dom::eventtarget::EventTarget; +use crate::dom::gamepad::{Gamepad, contains_user_gesture}; +use crate::dom::gamepadevent::GamepadEventType; use crate::dom::globalscope::GlobalScope; use crate::dom::hashchangeevent::HashChangeEvent; use crate::dom::history::History; @@ -642,6 +647,126 @@ impl Window { pub(crate) fn font_context(&self) -> &Arc<FontContext> { &self.font_context } + + pub(crate) fn handle_gamepad_event(&self, gamepad_event: GamepadEvent) { + match gamepad_event { + GamepadEvent::Connected(index, name, bounds, supported_haptic_effects) => { + self.handle_gamepad_connect( + index.0, + name, + bounds.axis_bounds, + bounds.button_bounds, + supported_haptic_effects, + ); + }, + GamepadEvent::Disconnected(index) => { + self.handle_gamepad_disconnect(index.0); + }, + GamepadEvent::Updated(index, update_type) => { + self.receive_new_gamepad_button_or_axis(index.0, update_type); + }, + }; + } + + /// <https://www.w3.org/TR/gamepad/#dfn-gamepadconnected> + fn handle_gamepad_connect( + &self, + // As the spec actually defines how to set the gamepad index, the GilRs index + // is currently unused, though in practice it will almost always be the same. + // More infra is currently needed to track gamepads across windows. + _index: usize, + name: String, + axis_bounds: (f64, f64), + button_bounds: (f64, f64), + supported_haptic_effects: GamepadSupportedHapticEffects, + ) { + // TODO: 2. If document is not null and is not allowed to use the "gamepad" permission, + // then abort these steps. + let this = Trusted::new(self); + self.upcast::<GlobalScope>() + .task_manager() + .gamepad_task_source() + .queue(task!(gamepad_connected: move || { + let window = this.root(); + + let navigator = window.Navigator(); + let selected_index = navigator.select_gamepad_index(); + let gamepad = Gamepad::new( + &window, + selected_index, + name, + "standard".into(), + axis_bounds, + button_bounds, + supported_haptic_effects, + false, + CanGc::note(), + ); + navigator.set_gamepad(selected_index as usize, &gamepad, CanGc::note()); + })); + } + + /// <https://www.w3.org/TR/gamepad/#dfn-gamepaddisconnected> + fn handle_gamepad_disconnect(&self, index: usize) { + let this = Trusted::new(self); + self.upcast::<GlobalScope>() + .task_manager() + .gamepad_task_source() + .queue(task!(gamepad_disconnected: move || { + let window = this.root(); + let navigator = window.Navigator(); + if let Some(gamepad) = navigator.get_gamepad(index) { + if window.Document().is_fully_active() { + gamepad.update_connected(false, gamepad.exposed(), CanGc::note()); + navigator.remove_gamepad(index); + } + } + })); + } + + /// <https://www.w3.org/TR/gamepad/#receiving-inputs> + fn receive_new_gamepad_button_or_axis(&self, index: usize, update_type: GamepadUpdateType) { + let this = Trusted::new(self); + + // <https://w3c.github.io/gamepad/#dfn-update-gamepad-state> + self.upcast::<GlobalScope>().task_manager().gamepad_task_source().queue( + task!(update_gamepad_state: move || { + let window = this.root(); + let navigator = window.Navigator(); + if let Some(gamepad) = navigator.get_gamepad(index) { + let current_time = window.Performance().Now(); + gamepad.update_timestamp(*current_time); + match update_type { + GamepadUpdateType::Axis(index, value) => { + gamepad.map_and_normalize_axes(index, value); + }, + GamepadUpdateType::Button(index, value) => { + gamepad.map_and_normalize_buttons(index, value); + } + }; + if !navigator.has_gamepad_gesture() && contains_user_gesture(update_type) { + navigator.set_has_gamepad_gesture(true); + navigator.GetGamepads() + .iter() + .filter_map(|g| g.as_ref()) + .for_each(|gamepad| { + gamepad.set_exposed(true); + gamepad.update_timestamp(*current_time); + let new_gamepad = Trusted::new(&**gamepad); + if window.Document().is_fully_active() { + window.upcast::<GlobalScope>().task_manager().gamepad_task_source().queue( + task!(update_gamepad_connect: move || { + let gamepad = new_gamepad.root(); + gamepad.notify_event(GamepadEventType::Connected, CanGc::note()); + }) + ); + } + }); + } + } + }) + ); + } } // https://html.spec.whatwg.org/multipage/#atob @@ -1246,7 +1371,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window { let rv = jsval_to_webdriver(cx, &self.globalscope, val, realm, can_gc); let opt_chan = self.webdriver_script_chan.borrow_mut().take(); if let Some(chan) = opt_chan { - chan.send(rv).unwrap(); + let _ = chan.send(rv); } } @@ -1255,9 +1380,9 @@ impl WindowMethods<crate::DomTypeHolder> for Window { let opt_chan = self.webdriver_script_chan.borrow_mut().take(); if let Some(chan) = opt_chan { if let Ok(rv) = rv { - chan.send(Err(WebDriverJSError::JSException(rv))).unwrap(); + let _ = chan.send(Err(WebDriverJSError::JSException(rv))); } else { - chan.send(rv).unwrap(); + let _ = chan.send(rv); } } } @@ -1265,7 +1390,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window { fn WebdriverTimeout(&self) { let opt_chan = self.webdriver_script_chan.borrow_mut().take(); if let Some(chan) = opt_chan { - chan.send(Err(WebDriverJSError::Timeout)).unwrap(); + let _ = chan.send(Err(WebDriverJSError::Timeout)); } } |