mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Implement Gamepad API
This commit is contained in:
parent
69eda6a60c
commit
0158b5b2af
27 changed files with 1193 additions and 96 deletions
|
@ -102,7 +102,6 @@ use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, Scri
|
|||
use script_traits::{LogEntry, ServiceWorkerMsg, webdriver_msg};
|
||||
use script_traits::{MozBrowserErrorType, MozBrowserEvent, WebDriverCommandMsg, WindowSizeData};
|
||||
use script_traits::{SWManagerMsg, ScopeThings, WindowSizeType};
|
||||
use script_traits::WebVREventMsg;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use servo_config::opts;
|
||||
use servo_config::prefs::PREFS;
|
||||
|
@ -124,7 +123,7 @@ use style_traits::cursor::Cursor;
|
|||
use style_traits::viewport::ViewportConstraints;
|
||||
use timer_scheduler::TimerScheduler;
|
||||
use webrender_traits;
|
||||
use webvr_traits::WebVRMsg;
|
||||
use webvr_traits::{WebVREvent, WebVRMsg};
|
||||
|
||||
/// The `Constellation` itself. In the servo browser, there is one
|
||||
/// constellation, which maintains all of the browser global data.
|
||||
|
@ -897,9 +896,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
assert!(self.webvr_thread.is_none());
|
||||
self.webvr_thread = Some(webvr_thread)
|
||||
}
|
||||
FromCompositorMsg::WebVREvent(pipeline_ids, event) => {
|
||||
debug!("constellation got WebVR event");
|
||||
self.handle_webvr_event(pipeline_ids, event);
|
||||
FromCompositorMsg::WebVREvents(pipeline_ids, events) => {
|
||||
debug!("constellation got {:?} WebVR events", events.len());
|
||||
self.handle_webvr_events(pipeline_ids, events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1326,12 +1325,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_webvr_event(&mut self, ids: Vec<PipelineId>, event: WebVREventMsg) {
|
||||
fn handle_webvr_events(&mut self, ids: Vec<PipelineId>, events: Vec<WebVREvent>) {
|
||||
for id in ids {
|
||||
match self.pipelines.get_mut(&id) {
|
||||
Some(ref pipeline) => {
|
||||
// Notify script thread
|
||||
let _ = pipeline.event_loop.send(ConstellationControlMsg::WebVREvent(id, event.clone()));
|
||||
let _ = pipeline.event_loop.send(ConstellationControlMsg::WebVREvents(id, events.clone()));
|
||||
},
|
||||
None => warn!("constellation got webvr event for dead pipeline")
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@ use time::Duration;
|
|||
use uuid::Uuid;
|
||||
use webrender_traits::{WebGLBufferId, WebGLError, WebGLFramebufferId, WebGLProgramId};
|
||||
use webrender_traits::{WebGLRenderbufferId, WebGLShaderId, WebGLTextureId};
|
||||
use webvr_traits::WebVRGamepadHand;
|
||||
|
||||
/// A trait to allow tracing (only) DOM objects.
|
||||
pub unsafe trait JSTraceable {
|
||||
|
@ -381,6 +382,7 @@ unsafe_no_jsmanaged_fields!(WebGLRenderbufferId);
|
|||
unsafe_no_jsmanaged_fields!(WebGLShaderId);
|
||||
unsafe_no_jsmanaged_fields!(WebGLTextureId);
|
||||
unsafe_no_jsmanaged_fields!(MediaList);
|
||||
unsafe_no_jsmanaged_fields!(WebVRGamepadHand);
|
||||
|
||||
unsafe impl<'a> JSTraceable for &'a str {
|
||||
#[inline]
|
||||
|
|
206
components/script/dom/gamepad.rs
Normal file
206
components/script/dom/gamepad.rs
Normal file
|
@ -0,0 +1,206 @@
|
|||
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use core::nonzero::NonZero;
|
||||
use dom::bindings::codegen::Bindings::GamepadBinding;
|
||||
use dom::bindings::codegen::Bindings::GamepadBinding::GamepadMethods;
|
||||
use dom::bindings::inheritance::Castable;
|
||||
use dom::bindings::js::{JS, Root};
|
||||
use dom::bindings::num::Finite;
|
||||
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
|
||||
use dom::bindings::str::DOMString;
|
||||
use dom::event::Event;
|
||||
use dom::eventtarget::EventTarget;
|
||||
use dom::gamepadbuttonlist::GamepadButtonList;
|
||||
use dom::gamepadevent::{GamepadEvent, GamepadEventType};
|
||||
use dom::globalscope::GlobalScope;
|
||||
use dom::vrpose::VRPose;
|
||||
use dom_struct::dom_struct;
|
||||
use js::jsapi::{Heap, JSContext, JSObject};
|
||||
use js::typedarray::{Float64Array, CreateWith};
|
||||
use std::cell::Cell;
|
||||
use std::ptr;
|
||||
use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct Gamepad {
|
||||
reflector_: Reflector,
|
||||
gamepad_id: u32,
|
||||
id: String,
|
||||
index: Cell<i32>,
|
||||
connected: Cell<bool>,
|
||||
timestamp: Cell<f64>,
|
||||
mapping_type: String,
|
||||
axes: Heap<*mut JSObject>,
|
||||
buttons: JS<GamepadButtonList>,
|
||||
pose: Option<JS<VRPose>>,
|
||||
#[ignore_heap_size_of = "Defined in rust-webvr"]
|
||||
hand: WebVRGamepadHand,
|
||||
display_id: u32
|
||||
}
|
||||
|
||||
impl Gamepad {
|
||||
fn new_inherited(gamepad_id: u32,
|
||||
id: String,
|
||||
index: i32,
|
||||
connected: bool,
|
||||
timestamp: f64,
|
||||
mapping_type: String,
|
||||
axes: *mut JSObject,
|
||||
buttons: &GamepadButtonList,
|
||||
pose: Option<&VRPose>,
|
||||
hand: WebVRGamepadHand,
|
||||
display_id: u32) -> Gamepad {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
gamepad_id: gamepad_id,
|
||||
id: id,
|
||||
index: Cell::new(index),
|
||||
connected: Cell::new(connected),
|
||||
timestamp: Cell::new(timestamp),
|
||||
mapping_type: mapping_type,
|
||||
axes: Heap::new(axes),
|
||||
buttons: JS::from_ref(buttons),
|
||||
pose: pose.map(JS::from_ref),
|
||||
hand: hand,
|
||||
display_id: display_id
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn new_from_vr(global: &GlobalScope,
|
||||
index: i32,
|
||||
data: &WebVRGamepadData,
|
||||
state: &WebVRGamepadState) -> Root<Gamepad> {
|
||||
let buttons = GamepadButtonList::new_from_vr(&global, &state.buttons);
|
||||
let pose = VRPose::new(&global, &state.pose);
|
||||
let cx = global.get_cx();
|
||||
rooted!(in (cx) let mut axes = ptr::null_mut());
|
||||
unsafe {
|
||||
let _ = Float64Array::create(cx,
|
||||
CreateWith::Slice(&state.axes),
|
||||
axes.handle_mut());
|
||||
}
|
||||
|
||||
reflect_dom_object(box Gamepad::new_inherited(state.gamepad_id,
|
||||
data.name.clone(),
|
||||
index,
|
||||
state.connected,
|
||||
state.timestamp,
|
||||
"".into(),
|
||||
axes.get(),
|
||||
&buttons,
|
||||
Some(&pose),
|
||||
data.hand.clone(),
|
||||
data.display_id),
|
||||
global,
|
||||
GamepadBinding::Wrap)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
impl GamepadMethods for Gamepad {
|
||||
// https://w3c.github.io/gamepad/#dom-gamepad-id
|
||||
fn Id(&self) -> DOMString {
|
||||
DOMString::from(self.id.clone())
|
||||
}
|
||||
|
||||
// https://w3c.github.io/gamepad/#dom-gamepad-index
|
||||
fn Index(&self) -> i32 {
|
||||
self.index.get()
|
||||
}
|
||||
|
||||
// https://w3c.github.io/gamepad/#dom-gamepad-connected
|
||||
fn Connected(&self) -> bool {
|
||||
self.connected.get()
|
||||
}
|
||||
|
||||
// https://w3c.github.io/gamepad/#dom-gamepad-timestamp
|
||||
fn Timestamp(&self) -> Finite<f64> {
|
||||
Finite::wrap(self.timestamp.get())
|
||||
}
|
||||
|
||||
// https://w3c.github.io/gamepad/#dom-gamepad-mapping
|
||||
fn Mapping(&self) -> DOMString {
|
||||
DOMString::from(self.mapping_type.clone())
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
// https://w3c.github.io/gamepad/#dom-gamepad-axes
|
||||
unsafe fn Axes(&self, _cx: *mut JSContext) -> NonZero<*mut JSObject> {
|
||||
NonZero::new(self.axes.get())
|
||||
}
|
||||
|
||||
// https://w3c.github.io/gamepad/#dom-gamepad-buttons
|
||||
fn Buttons(&self) -> Root<GamepadButtonList> {
|
||||
Root::from_ref(&*self.buttons)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/gamepad/extensions.html#gamepadhand-enum
|
||||
fn Hand(&self) -> DOMString {
|
||||
let value = match self.hand {
|
||||
WebVRGamepadHand::Unknown => "",
|
||||
WebVRGamepadHand::Left => "left",
|
||||
WebVRGamepadHand::Right => "right"
|
||||
};
|
||||
value.into()
|
||||
}
|
||||
|
||||
// https://w3c.github.io/gamepad/extensions.html#dom-gamepad-pose
|
||||
fn GetPose(&self) -> Option<Root<VRPose>> {
|
||||
self.pose.as_ref().map(|p| Root::from_ref(&**p))
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/spec/1.1/#gamepad-getvrdisplays-attribute
|
||||
fn DisplayId(&self) -> u32 {
|
||||
self.display_id
|
||||
}
|
||||
}
|
||||
|
||||
impl Gamepad {
|
||||
#[allow(unsafe_code)]
|
||||
pub fn update_from_vr(&self, state: &WebVRGamepadState) {
|
||||
self.timestamp.set(state.timestamp);
|
||||
unsafe {
|
||||
let cx = self.global().get_cx();
|
||||
typedarray!(in(cx) let axes: Float64Array = self.axes.get());
|
||||
if let Ok(mut array) = axes {
|
||||
array.update(&state.axes);
|
||||
}
|
||||
}
|
||||
self.buttons.sync_from_vr(&state.buttons);
|
||||
if let Some(ref pose) = self.pose {
|
||||
pose.update(&state.pose);
|
||||
}
|
||||
self.update_connected(state.connected);
|
||||
}
|
||||
|
||||
pub fn gamepad_id(&self) -> u32 {
|
||||
self.gamepad_id
|
||||
}
|
||||
|
||||
pub fn update_connected(&self, connected: bool) {
|
||||
if self.connected.get() == connected {
|
||||
return;
|
||||
}
|
||||
self.connected.set(connected);
|
||||
|
||||
let event_type = if connected {
|
||||
GamepadEventType::Connected
|
||||
} else {
|
||||
GamepadEventType::Disconnected
|
||||
};
|
||||
|
||||
self.notify_event(event_type);
|
||||
}
|
||||
|
||||
pub fn update_index(&self, index: i32) {
|
||||
self.index.set(index);
|
||||
}
|
||||
|
||||
pub fn notify_event(&self, event_type: GamepadEventType) {
|
||||
let event = GamepadEvent::new_with_type(&self.global(), event_type, &self);
|
||||
event.upcast::<Event>().fire(self.global().as_window().upcast::<EventTarget>());
|
||||
}
|
||||
}
|
61
components/script/dom/gamepadbutton.rs
Normal file
61
components/script/dom/gamepadbutton.rs
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom::bindings::codegen::Bindings::GamepadButtonBinding;
|
||||
use dom::bindings::codegen::Bindings::GamepadButtonBinding::GamepadButtonMethods;
|
||||
use dom::bindings::js::Root;
|
||||
use dom::bindings::num::Finite;
|
||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use dom::globalscope::GlobalScope;
|
||||
use dom_struct::dom_struct;
|
||||
use std::cell::Cell;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GamepadButton {
|
||||
reflector_: Reflector,
|
||||
pressed: Cell<bool>,
|
||||
touched: Cell<bool>,
|
||||
value: Cell<f64>,
|
||||
}
|
||||
|
||||
impl GamepadButton {
|
||||
pub fn new_inherited(pressed: bool, touched: bool) -> GamepadButton {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
pressed: Cell::new(pressed),
|
||||
touched: Cell::new(touched),
|
||||
value: Cell::new(0.0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope, pressed: bool, touched: bool) -> Root<GamepadButton> {
|
||||
reflect_dom_object(box GamepadButton::new_inherited(pressed, touched),
|
||||
global,
|
||||
GamepadButtonBinding::Wrap)
|
||||
}
|
||||
}
|
||||
|
||||
impl GamepadButtonMethods for GamepadButton {
|
||||
// https://www.w3.org/TR/gamepad/#widl-GamepadButton-pressed
|
||||
fn Pressed(&self) -> bool {
|
||||
self.pressed.get()
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/gamepad/#widl-GamepadButton-touched
|
||||
fn Touched(&self) -> bool {
|
||||
self.touched.get()
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/gamepad/#widl-GamepadButton-value
|
||||
fn Value(&self) -> Finite<f64> {
|
||||
Finite::wrap(self.value.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl GamepadButton {
|
||||
pub fn update(&self, pressed: bool, touched: bool) {
|
||||
self.pressed.set(pressed);
|
||||
self.touched.set(touched);
|
||||
}
|
||||
}
|
63
components/script/dom/gamepadbuttonlist.rs
Normal file
63
components/script/dom/gamepadbuttonlist.rs
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom::bindings::codegen::Bindings::GamepadButtonListBinding;
|
||||
use dom::bindings::codegen::Bindings::GamepadButtonListBinding::GamepadButtonListMethods;
|
||||
use dom::bindings::js::{JS, Root, RootedReference};
|
||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use dom::gamepadbutton::GamepadButton;
|
||||
use dom::globalscope::GlobalScope;
|
||||
use dom_struct::dom_struct;
|
||||
use webvr_traits::WebVRGamepadButton;
|
||||
|
||||
// https://w3c.github.io/gamepad/#gamepadbutton-interface
|
||||
#[dom_struct]
|
||||
pub struct GamepadButtonList {
|
||||
reflector_: Reflector,
|
||||
list: Vec<JS<GamepadButton>>
|
||||
}
|
||||
|
||||
impl GamepadButtonList {
|
||||
#[allow(unrooted_must_root)]
|
||||
fn new_inherited(list: &[&GamepadButton]) -> GamepadButtonList {
|
||||
GamepadButtonList {
|
||||
reflector_: Reflector::new(),
|
||||
list: list.iter().map(|button| JS::from_ref(*button)).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_from_vr(global: &GlobalScope, buttons: &[WebVRGamepadButton]) -> Root<GamepadButtonList> {
|
||||
rooted_vec!(let list <- buttons.iter()
|
||||
.map(|btn| GamepadButton::new(&global, btn.pressed, btn.touched)));
|
||||
|
||||
reflect_dom_object(box GamepadButtonList::new_inherited(list.r()),
|
||||
global,
|
||||
GamepadButtonListBinding::Wrap)
|
||||
}
|
||||
|
||||
pub fn sync_from_vr(&self, vr_buttons: &[WebVRGamepadButton]) {
|
||||
let mut index = 0;
|
||||
for btn in vr_buttons {
|
||||
self.list.get(index).as_ref().unwrap().update(btn.pressed, btn.touched);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GamepadButtonListMethods for GamepadButtonList {
|
||||
// https://w3c.github.io/gamepad/#dom-gamepad-buttons
|
||||
fn Length(&self) -> u32 {
|
||||
self.list.len() as u32
|
||||
}
|
||||
|
||||
// https://w3c.github.io/gamepad/#dom-gamepad-buttons
|
||||
fn Item(&self, index: u32) -> Option<Root<GamepadButton>> {
|
||||
self.list.get(index as usize).map(|button| Root::from_ref(&**button))
|
||||
}
|
||||
|
||||
// https://w3c.github.io/gamepad/#dom-gamepad-buttons
|
||||
fn IndexedGetter(&self, index: u32) -> Option<Root<GamepadButton>> {
|
||||
self.Item(index)
|
||||
}
|
||||
}
|
92
components/script/dom/gamepadevent.rs
Normal file
92
components/script/dom/gamepadevent.rs
Normal file
|
@ -0,0 +1,92 @@
|
|||
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom::bindings::codegen::Bindings::EventBinding::EventBinding::EventMethods;
|
||||
use dom::bindings::codegen::Bindings::GamepadEventBinding;
|
||||
use dom::bindings::codegen::Bindings::GamepadEventBinding::GamepadEventMethods;
|
||||
use dom::bindings::error::Fallible;
|
||||
use dom::bindings::inheritance::Castable;
|
||||
use dom::bindings::js::{JS, Root};
|
||||
use dom::bindings::reflector::{DomObject, reflect_dom_object};
|
||||
use dom::bindings::str::DOMString;
|
||||
use dom::event::Event;
|
||||
use dom::gamepad::Gamepad;
|
||||
use dom::globalscope::GlobalScope;
|
||||
use dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
use servo_atoms::Atom;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GamepadEvent {
|
||||
event: Event,
|
||||
gamepad: JS<Gamepad>,
|
||||
}
|
||||
|
||||
pub enum GamepadEventType {
|
||||
Connected,
|
||||
Disconnected
|
||||
}
|
||||
|
||||
impl GamepadEvent {
|
||||
fn new_inherited(gamepad: &Gamepad) -> GamepadEvent {
|
||||
GamepadEvent {
|
||||
event: Event::new_inherited(),
|
||||
gamepad: JS::from_ref(gamepad),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope,
|
||||
type_: Atom,
|
||||
bubbles: bool,
|
||||
cancelable: bool,
|
||||
gamepad: &Gamepad)
|
||||
-> Root<GamepadEvent> {
|
||||
let ev = reflect_dom_object(box GamepadEvent::new_inherited(&gamepad),
|
||||
global,
|
||||
GamepadEventBinding::Wrap);
|
||||
{
|
||||
let event = ev.upcast::<Event>();
|
||||
event.init_event(type_, bubbles, cancelable);
|
||||
}
|
||||
ev
|
||||
}
|
||||
|
||||
pub fn new_with_type(global: &GlobalScope, event_type: GamepadEventType, gamepad: &Gamepad)
|
||||
-> Root<GamepadEvent> {
|
||||
let name = match event_type {
|
||||
GamepadEventType::Connected => "gamepadconnected",
|
||||
GamepadEventType::Disconnected => "gamepaddisconnected"
|
||||
};
|
||||
|
||||
GamepadEvent::new(&global,
|
||||
name.into(),
|
||||
false,
|
||||
false,
|
||||
&gamepad)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/gamepad/#gamepadevent-interface
|
||||
pub fn Constructor(window: &Window,
|
||||
type_: DOMString,
|
||||
init: &GamepadEventBinding::GamepadEventInit)
|
||||
-> Fallible<Root<GamepadEvent>> {
|
||||
Ok(GamepadEvent::new(&window.global(),
|
||||
Atom::from(type_),
|
||||
init.parent.bubbles,
|
||||
init.parent.cancelable,
|
||||
&init.gamepad))
|
||||
}
|
||||
}
|
||||
|
||||
impl GamepadEventMethods for GamepadEvent {
|
||||
// https://w3c.github.io/gamepad/#gamepadevent-interface
|
||||
fn Gamepad(&self) -> Root<Gamepad> {
|
||||
Root::from_ref(&*self.gamepad)
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-istrusted
|
||||
fn IsTrusted(&self) -> bool {
|
||||
self.event.IsTrusted()
|
||||
}
|
||||
}
|
61
components/script/dom/gamepadlist.rs
Normal file
61
components/script/dom/gamepadlist.rs
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom::bindings::cell::DOMRefCell;
|
||||
use dom::bindings::codegen::Bindings::GamepadListBinding;
|
||||
use dom::bindings::codegen::Bindings::GamepadListBinding::GamepadListMethods;
|
||||
use dom::bindings::js::{JS, Root};
|
||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use dom::gamepad::Gamepad;
|
||||
use dom::globalscope::GlobalScope;
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
// https://www.w3.org/TR/gamepad/
|
||||
#[dom_struct]
|
||||
pub struct GamepadList {
|
||||
reflector_: Reflector,
|
||||
list: DOMRefCell<Vec<JS<Gamepad>>>
|
||||
}
|
||||
|
||||
impl GamepadList {
|
||||
fn new_inherited(list: &[&Gamepad]) -> GamepadList {
|
||||
GamepadList {
|
||||
reflector_: Reflector::new(),
|
||||
list: DOMRefCell::new(list.iter().map(|g| JS::from_ref(&**g)).collect())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope, list: &[&Gamepad]) -> Root<GamepadList> {
|
||||
reflect_dom_object(box GamepadList::new_inherited(list),
|
||||
global,
|
||||
GamepadListBinding::Wrap)
|
||||
}
|
||||
|
||||
pub fn add_if_not_exists(&self, gamepads: &[Root<Gamepad>]) {
|
||||
for gamepad in gamepads {
|
||||
if !self.list.borrow().iter().any(|g| g.gamepad_id() == gamepad.gamepad_id()) {
|
||||
self.list.borrow_mut().push(JS::from_ref(&*gamepad));
|
||||
// Ensure that the gamepad has the correct index
|
||||
gamepad.update_index(self.list.borrow().len() as i32 - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GamepadListMethods for GamepadList {
|
||||
// https://w3c.github.io/gamepad/#dom-navigator-getgamepads
|
||||
fn Length(&self) -> u32 {
|
||||
self.list.borrow().len() as u32
|
||||
}
|
||||
|
||||
// https://w3c.github.io/gamepad/#dom-navigator-getgamepads
|
||||
fn Item(&self, index: u32) -> Option<Root<Gamepad>> {
|
||||
self.list.borrow().get(index as usize).map(|gamepad| Root::from_ref(&**gamepad))
|
||||
}
|
||||
|
||||
// https://w3c.github.io/gamepad/#dom-navigator-getgamepads
|
||||
fn IndexedGetter(&self, index: u32) -> Option<Root<Gamepad>> {
|
||||
self.Item(index)
|
||||
}
|
||||
}
|
|
@ -290,6 +290,11 @@ pub mod filereadersync;
|
|||
pub mod focusevent;
|
||||
pub mod forcetouchevent;
|
||||
pub mod formdata;
|
||||
pub mod gamepad;
|
||||
pub mod gamepadbutton;
|
||||
pub mod gamepadbuttonlist;
|
||||
pub mod gamepadevent;
|
||||
pub mod gamepadlist;
|
||||
pub mod globalscope;
|
||||
pub mod hashchangeevent;
|
||||
pub mod headers;
|
||||
|
|
|
@ -8,6 +8,7 @@ use dom::bindings::js::{MutNullableJS, Root};
|
|||
use dom::bindings::reflector::{Reflector, DomObject, reflect_dom_object};
|
||||
use dom::bindings::str::DOMString;
|
||||
use dom::bluetooth::Bluetooth;
|
||||
use dom::gamepadlist::GamepadList;
|
||||
use dom::mimetypearray::MimeTypeArray;
|
||||
use dom::navigatorinfo;
|
||||
use dom::permissions::Permissions;
|
||||
|
@ -16,7 +17,6 @@ use dom::serviceworkercontainer::ServiceWorkerContainer;
|
|||
use dom::vr::VR;
|
||||
use dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
use script_traits::WebVREventMsg;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct Navigator {
|
||||
|
@ -26,6 +26,7 @@ pub struct Navigator {
|
|||
mime_types: MutNullableJS<MimeTypeArray>,
|
||||
service_worker: MutNullableJS<ServiceWorkerContainer>,
|
||||
vr: MutNullableJS<VR>,
|
||||
gamepads: MutNullableJS<GamepadList>,
|
||||
permissions: MutNullableJS<Permissions>,
|
||||
}
|
||||
|
||||
|
@ -38,6 +39,7 @@ impl Navigator {
|
|||
mime_types: Default::default(),
|
||||
service_worker: Default::default(),
|
||||
vr: Default::default(),
|
||||
gamepads: Default::default(),
|
||||
permissions: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -128,15 +130,19 @@ impl NavigatorMethods for Navigator {
|
|||
self.vr.or_init(|| VR::new(&self.global()))
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/gamepad/#navigator-interface-extension
|
||||
fn GetGamepads(&self) -> Root<GamepadList> {
|
||||
let root = self.gamepads.or_init(|| {
|
||||
GamepadList::new(&self.global(), &[])
|
||||
});
|
||||
|
||||
let vr_gamepads = self.Vr().get_gamepads();
|
||||
root.add_if_not_exists(&vr_gamepads);
|
||||
// TODO: Add not VR related gamepads
|
||||
root
|
||||
}
|
||||
// https://w3c.github.io/permissions/#navigator-and-workernavigator-extension
|
||||
fn Permissions(&self) -> Root<Permissions> {
|
||||
self.permissions.or_init(|| Permissions::new(&self.global()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Navigator {
|
||||
pub fn handle_webvr_event(&self, event: WebVREventMsg) {
|
||||
self.vr.get().expect("Shouldn't arrive here with an empty VR instance")
|
||||
.handle_webvr_event(event);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,15 @@
|
|||
use dom::bindings::cell::DOMRefCell;
|
||||
use dom::bindings::codegen::Bindings::VRBinding;
|
||||
use dom::bindings::codegen::Bindings::VRBinding::VRMethods;
|
||||
use dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods;
|
||||
use dom::bindings::error::Error;
|
||||
use dom::bindings::inheritance::Castable;
|
||||
use dom::bindings::js::{JS, Root};
|
||||
use dom::bindings::reflector::{DomObject, reflect_dom_object};
|
||||
use dom::event::Event;
|
||||
use dom::eventtarget::EventTarget;
|
||||
use dom::gamepad::Gamepad;
|
||||
use dom::gamepadevent::GamepadEventType;
|
||||
use dom::globalscope::GlobalScope;
|
||||
use dom::promise::Promise;
|
||||
use dom::vrdisplay::VRDisplay;
|
||||
|
@ -18,22 +21,23 @@ use dom::vrdisplayevent::VRDisplayEvent;
|
|||
use dom_struct::dom_struct;
|
||||
use ipc_channel::ipc;
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use script_traits::WebVREventMsg;
|
||||
use std::rc::Rc;
|
||||
use webvr_traits::WebVRMsg;
|
||||
use webvr_traits::webvr;
|
||||
use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVREvent, WebVRMsg};
|
||||
use webvr_traits::{WebVRGamepadData, WebVRGamepadEvent, WebVRGamepadState};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct VR {
|
||||
eventtarget: EventTarget,
|
||||
displays: DOMRefCell<Vec<JS<VRDisplay>>>
|
||||
displays: DOMRefCell<Vec<JS<VRDisplay>>>,
|
||||
gamepads: DOMRefCell<Vec<JS<Gamepad>>>
|
||||
}
|
||||
|
||||
impl VR {
|
||||
fn new_inherited() -> VR {
|
||||
VR {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
displays: DOMRefCell::new(Vec::new())
|
||||
displays: DOMRefCell::new(Vec::new()),
|
||||
gamepads: DOMRefCell::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,10 +99,10 @@ impl VR {
|
|||
self.global().as_window().webvr_thread()
|
||||
}
|
||||
|
||||
fn find_display(&self, display_id: u64) -> Option<Root<VRDisplay>> {
|
||||
fn find_display(&self, display_id: u32) -> Option<Root<VRDisplay>> {
|
||||
self.displays.borrow()
|
||||
.iter()
|
||||
.find(|d| d.get_display_id() == display_id)
|
||||
.find(|d| d.DisplayId() == display_id)
|
||||
.map(|d| Root::from_ref(&**d))
|
||||
}
|
||||
|
||||
|
@ -116,7 +120,7 @@ impl VR {
|
|||
}
|
||||
}
|
||||
|
||||
fn sync_display(&self, display: &webvr::VRDisplayData) -> Root<VRDisplay> {
|
||||
fn sync_display(&self, display: &WebVRDisplayData) -> Root<VRDisplay> {
|
||||
if let Some(existing) = self.find_display(display.display_id) {
|
||||
existing.update_display(&display);
|
||||
existing
|
||||
|
@ -127,35 +131,121 @@ impl VR {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn handle_webvr_event(&self, event: WebVREventMsg) {
|
||||
let WebVREventMsg::DisplayEvent(event) = event;
|
||||
match &event {
|
||||
&webvr::VRDisplayEvent::Connect(ref display) => {
|
||||
fn handle_display_event(&self, event: WebVRDisplayEvent) {
|
||||
match event {
|
||||
WebVRDisplayEvent::Connect(ref display) => {
|
||||
let display = self.sync_display(&display);
|
||||
display.handle_webvr_event(&event);
|
||||
self.notify_event(&display, &event);
|
||||
self.notify_display_event(&display, &event);
|
||||
},
|
||||
&webvr::VRDisplayEvent::Disconnect(id) => {
|
||||
WebVRDisplayEvent::Disconnect(id) => {
|
||||
if let Some(display) = self.find_display(id) {
|
||||
display.handle_webvr_event(&event);
|
||||
self.notify_event(&display, &event);
|
||||
self.notify_display_event(&display, &event);
|
||||
}
|
||||
},
|
||||
&webvr::VRDisplayEvent::Activate(ref display, _) |
|
||||
&webvr::VRDisplayEvent::Deactivate(ref display, _) |
|
||||
&webvr::VRDisplayEvent::Blur(ref display) |
|
||||
&webvr::VRDisplayEvent::Focus(ref display) |
|
||||
&webvr::VRDisplayEvent::PresentChange(ref display, _) |
|
||||
&webvr::VRDisplayEvent::Change(ref display) => {
|
||||
WebVRDisplayEvent::Activate(ref display, _) |
|
||||
WebVRDisplayEvent::Deactivate(ref display, _) |
|
||||
WebVRDisplayEvent::Blur(ref display) |
|
||||
WebVRDisplayEvent::Focus(ref display) |
|
||||
WebVRDisplayEvent::PresentChange(ref display, _) |
|
||||
WebVRDisplayEvent::Change(ref display) => {
|
||||
let display = self.sync_display(&display);
|
||||
display.handle_webvr_event(&event);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn notify_event(&self, display: &VRDisplay, event: &webvr::VRDisplayEvent) {
|
||||
fn handle_gamepad_event(&self, event: WebVRGamepadEvent) {
|
||||
match event {
|
||||
WebVRGamepadEvent::Connect(data, state) => {
|
||||
if let Some(gamepad) = self.find_gamepad(state.gamepad_id) {
|
||||
gamepad.update_from_vr(&state);
|
||||
} else {
|
||||
// new gamepad
|
||||
self.sync_gamepad(Some(data), &state);
|
||||
}
|
||||
},
|
||||
WebVRGamepadEvent::Disconnect(id) => {
|
||||
if let Some(gamepad) = self.find_gamepad(id) {
|
||||
gamepad.update_connected(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn handle_webvr_event(&self, event: WebVREvent) {
|
||||
match event {
|
||||
WebVREvent::Display(event) => {
|
||||
self.handle_display_event(event);
|
||||
},
|
||||
WebVREvent::Gamepad(event) => {
|
||||
self.handle_gamepad_event(event);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn handle_webvr_events(&self, events: Vec<WebVREvent>) {
|
||||
for event in events {
|
||||
self.handle_webvr_event(event);
|
||||
}
|
||||
}
|
||||
|
||||
fn notify_display_event(&self, display: &VRDisplay, event: &WebVRDisplayEvent) {
|
||||
let event = VRDisplayEvent::new_from_webvr(&self.global(), &display, &event);
|
||||
event.upcast::<Event>().fire(self.upcast());
|
||||
}
|
||||
}
|
||||
|
||||
// Gamepad
|
||||
impl VR {
|
||||
fn find_gamepad(&self, gamepad_id: u32) -> Option<Root<Gamepad>> {
|
||||
self.gamepads.borrow()
|
||||
.iter()
|
||||
.find(|g| g.gamepad_id() == gamepad_id)
|
||||
.map(|g| Root::from_ref(&**g))
|
||||
}
|
||||
|
||||
fn sync_gamepad(&self, data: Option<WebVRGamepadData>, state: &WebVRGamepadState) {
|
||||
if let Some(existing) = self.find_gamepad(state.gamepad_id) {
|
||||
existing.update_from_vr(&state);
|
||||
} else {
|
||||
let index = self.gamepads.borrow().len();
|
||||
let data = data.unwrap_or_default();
|
||||
let root = Gamepad::new_from_vr(&self.global(),
|
||||
index as i32,
|
||||
&data,
|
||||
&state);
|
||||
self.gamepads.borrow_mut().push(JS::from_ref(&*root));
|
||||
if state.connected {
|
||||
root.notify_event(GamepadEventType::Connected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gamepads are synced immediately in response to the API call.
|
||||
// The current approach allows the to sample gamepad state multiple times per frame. This
|
||||
// guarantees that the gamepads always have a valid state and can be very useful for
|
||||
// motion capture or drawing applications.
|
||||
pub fn get_gamepads(&self) -> Vec<Root<Gamepad>> {
|
||||
if let Some(wevbr_sender) = self.webvr_thread() {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
let synced_ids = self.gamepads.borrow().iter().map(|g| g.gamepad_id()).collect();
|
||||
wevbr_sender.send(WebVRMsg::GetGamepads(synced_ids, sender)).unwrap();
|
||||
match receiver.recv().unwrap() {
|
||||
Ok(gamepads) => {
|
||||
// Sync displays
|
||||
for gamepad in gamepads {
|
||||
self.sync_gamepad(gamepad.0, &gamepad.1);
|
||||
}
|
||||
},
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
// We can add other not VR related gamepad providers here
|
||||
self.gamepads.borrow().iter()
|
||||
.map(|g| Root::from_ref(&**g))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,7 +161,7 @@ impl VRDisplayMethods for VRDisplay {
|
|||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-displayid
|
||||
fn DisplayId(&self) -> u32 {
|
||||
self.display.borrow().display_id as u32
|
||||
self.display.borrow().display_id
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webvr/#dom-vrdisplay-displayname
|
||||
|
@ -188,7 +188,7 @@ impl VRDisplayMethods for VRDisplay {
|
|||
// If not presenting we fetch inmediante VRFrameData
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
self.webvr_thread().send(WebVRMsg::GetFrameData(self.global().pipeline_id(),
|
||||
self.get_display_id(),
|
||||
self.DisplayId(),
|
||||
self.depth_near.get(),
|
||||
self.depth_far.get(),
|
||||
sender)).unwrap();
|
||||
|
@ -213,7 +213,7 @@ impl VRDisplayMethods for VRDisplay {
|
|||
fn ResetPose(&self) {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
self.webvr_thread().send(WebVRMsg::ResetPose(self.global().pipeline_id(),
|
||||
self.get_display_id(),
|
||||
self.DisplayId(),
|
||||
sender)).unwrap();
|
||||
if let Ok(data) = receiver.recv().unwrap() {
|
||||
// Some VRDisplay data might change after calling ResetPose()
|
||||
|
@ -378,7 +378,7 @@ impl VRDisplayMethods for VRDisplay {
|
|||
}
|
||||
|
||||
let api_sender = self.layer_ctx.get().unwrap().ipc_renderer();
|
||||
let display_id = self.display.borrow().display_id;
|
||||
let display_id = self.display.borrow().display_id as u64;
|
||||
let layer = self.layer.borrow();
|
||||
let msg = VRCompositorCommand::SubmitFrame(display_id, layer.left_bounds, layer.right_bounds);
|
||||
api_sender.send(CanvasMsg::WebVR(msg)).unwrap();
|
||||
|
@ -390,10 +390,6 @@ impl VRDisplay {
|
|||
self.global().as_window().webvr_thread().expect("Shouldn't arrive here with WebVR disabled")
|
||||
}
|
||||
|
||||
pub fn get_display_id(&self) -> u64 {
|
||||
self.display.borrow().display_id
|
||||
}
|
||||
|
||||
pub fn update_display(&self, display: &WebVRDisplayData) {
|
||||
*self.display.borrow_mut() = display.clone();
|
||||
if let Some(ref stage) = display.stage_parameters {
|
||||
|
@ -447,7 +443,7 @@ impl VRDisplay {
|
|||
let (sync_sender, sync_receiver) = ipc::channel().unwrap();
|
||||
*self.frame_data_receiver.borrow_mut() = Some(sync_receiver);
|
||||
|
||||
let display_id = self.display.borrow().display_id;
|
||||
let display_id = self.display.borrow().display_id as u64;
|
||||
let api_sender = self.layer_ctx.get().unwrap().ipc_renderer();
|
||||
let js_sender = self.global().script_chan();
|
||||
let address = Trusted::new(&*self);
|
||||
|
@ -497,7 +493,7 @@ impl VRDisplay {
|
|||
*self.frame_data_receiver.borrow_mut() = None;
|
||||
|
||||
let api_sender = self.layer_ctx.get().unwrap().ipc_renderer();
|
||||
let display_id = self.display.borrow().display_id;
|
||||
let display_id = self.display.borrow().display_id as u64;
|
||||
let msg = VRCompositorCommand::Release(display_id);
|
||||
api_sender.send(CanvasMsg::WebVR(msg)).unwrap();
|
||||
}
|
||||
|
|
|
@ -32,7 +32,9 @@ unsafe fn update_or_create_typed_array(cx: *mut JSContext,
|
|||
match src {
|
||||
Some(data) => {
|
||||
if dst.get().is_null() {
|
||||
let _ = Float32Array::create(cx, CreateWith::Slice(data), dst.handle_mut());
|
||||
rooted!(in (cx) let mut array = ptr::null_mut());
|
||||
let _ = Float32Array::create(cx, CreateWith::Slice(data), array.handle_mut());
|
||||
(*dst).set(array.get());
|
||||
} else {
|
||||
typedarray!(in(cx) let array: Float32Array = dst.get());
|
||||
if let Ok(mut array) = array {
|
||||
|
|
26
components/script/dom/webidls/Gamepad.webidl
Normal file
26
components/script/dom/webidls/Gamepad.webidl
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// https://w3c.github.io/gamepad/#gamepad-interface
|
||||
[Pref="dom.gamepad.enabled"]
|
||||
interface Gamepad {
|
||||
readonly attribute DOMString id;
|
||||
readonly attribute long index;
|
||||
readonly attribute boolean connected;
|
||||
readonly attribute DOMHighResTimeStamp timestamp;
|
||||
readonly attribute DOMString mapping;
|
||||
readonly attribute Float64Array axes;
|
||||
[SameObject] readonly attribute GamepadButtonList buttons;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/gamepad/extensions.html#dom-gamepad
|
||||
partial interface Gamepad {
|
||||
readonly attribute DOMString hand;
|
||||
readonly attribute VRPose? pose;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/webvr/spec/1.1/#interface-gamepad
|
||||
partial interface Gamepad {
|
||||
readonly attribute unsigned long displayId;
|
||||
};
|
11
components/script/dom/webidls/GamepadButton.webidl
Normal file
11
components/script/dom/webidls/GamepadButton.webidl
Normal file
|
@ -0,0 +1,11 @@
|
|||
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// https://w3c.github.io/gamepad/#gamepadbutton-interface
|
||||
[Pref="dom.gamepad.enabled"]
|
||||
interface GamepadButton {
|
||||
readonly attribute boolean pressed;
|
||||
readonly attribute boolean touched;
|
||||
readonly attribute double value;
|
||||
};
|
10
components/script/dom/webidls/GamepadButtonList.webidl
Normal file
10
components/script/dom/webidls/GamepadButtonList.webidl
Normal file
|
@ -0,0 +1,10 @@
|
|||
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// https://w3c.github.io/gamepad/#dom-gamepad-buttons
|
||||
[Pref="dom.gamepad.enabled"]
|
||||
interface GamepadButtonList {
|
||||
getter GamepadButton? item(unsigned long index);
|
||||
readonly attribute unsigned long length;
|
||||
};
|
13
components/script/dom/webidls/GamepadEvent.webidl
Normal file
13
components/script/dom/webidls/GamepadEvent.webidl
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// https://w3c.github.io/gamepad/#gamepadevent-interface
|
||||
[Pref="dom.gamepad.enabled", Constructor(DOMString type, GamepadEventInit eventInitDict)]
|
||||
interface GamepadEvent : Event {
|
||||
readonly attribute Gamepad gamepad;
|
||||
};
|
||||
|
||||
dictionary GamepadEventInit : EventInit {
|
||||
required Gamepad gamepad;
|
||||
};
|
10
components/script/dom/webidls/GamepadList.webidl
Normal file
10
components/script/dom/webidls/GamepadList.webidl
Normal file
|
@ -0,0 +1,10 @@
|
|||
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// https://w3c.github.io/gamepad/#navigator-interface-extension
|
||||
[Pref="dom.gamepad.enabled"]
|
||||
interface GamepadList {
|
||||
getter Gamepad? item(unsigned long index);
|
||||
readonly attribute unsigned long length;
|
||||
};
|
|
@ -68,3 +68,8 @@ partial interface Navigator {
|
|||
partial interface Navigator {
|
||||
[Pref="dom.permissions.enabled"] readonly attribute Permissions permissions;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/gamepad/#navigator-interface-extension
|
||||
partial interface Navigator {
|
||||
[Pref="dom.gamepad.enabled"] GamepadList getGamepads();
|
||||
};
|
||||
|
|
|
@ -27,6 +27,7 @@ use dom::bindings::cell::DOMRefCell;
|
|||
use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
|
||||
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState};
|
||||
use dom::bindings::codegen::Bindings::EventBinding::EventInit;
|
||||
use dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods;
|
||||
use dom::bindings::codegen::Bindings::TransitionEventBinding::TransitionEventInit;
|
||||
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
||||
use dom::bindings::conversions::{ConversionResult, FromJSValConvertible, StringificationBehavior};
|
||||
|
@ -91,7 +92,6 @@ use script_traits::{ScriptThreadFactory, TimerEvent, TimerSchedulerMsg, TimerSou
|
|||
use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress, WindowSizeData, WindowSizeType};
|
||||
use script_traits::CompositorEvent::{KeyEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent};
|
||||
use script_traits::CompositorEvent::{TouchEvent, TouchpadPressureEvent};
|
||||
use script_traits::WebVREventMsg;
|
||||
use script_traits::webdriver_msg::WebDriverScriptCommand;
|
||||
use serviceworkerjob::{Job, JobQueue, AsyncJobHandler};
|
||||
use servo_config::opts;
|
||||
|
@ -119,7 +119,7 @@ use task_source::user_interaction::{UserInteractionTask, UserInteractionTaskSour
|
|||
use time::Tm;
|
||||
use url::Position;
|
||||
use webdriver_handlers;
|
||||
use webvr_traits::WebVRMsg;
|
||||
use webvr_traits::{WebVREvent, WebVRMsg};
|
||||
|
||||
pub type ImageCacheMsg = (PipelineId, PendingImageResponse);
|
||||
|
||||
|
@ -1070,8 +1070,8 @@ impl ScriptThread {
|
|||
self.handle_reload(pipeline_id),
|
||||
ConstellationControlMsg::ExitPipeline(pipeline_id, discard_browsing_context) =>
|
||||
self.handle_exit_pipeline_msg(pipeline_id, discard_browsing_context),
|
||||
ConstellationControlMsg::WebVREvent(pipeline_id, event) =>
|
||||
self.handle_webvr_event(pipeline_id, event),
|
||||
ConstellationControlMsg::WebVREvents(pipeline_id, events) =>
|
||||
self.handle_webvr_events(pipeline_id, events),
|
||||
msg @ ConstellationControlMsg::AttachLayout(..) |
|
||||
msg @ ConstellationControlMsg::Viewport(..) |
|
||||
msg @ ConstellationControlMsg::SetScrollState(..) |
|
||||
|
@ -2186,11 +2186,11 @@ impl ScriptThread {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_webvr_event(&self, pipeline_id: PipelineId, event: WebVREventMsg) {
|
||||
fn handle_webvr_events(&self, pipeline_id: PipelineId, events: Vec<WebVREvent>) {
|
||||
let window = self.documents.borrow().find_window(pipeline_id);
|
||||
if let Some(window) = window {
|
||||
let navigator = window.Navigator();
|
||||
navigator.handle_webvr_event(event);
|
||||
let vr = window.Navigator().Vr();
|
||||
vr.handle_webvr_events(events);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ use std::sync::Arc;
|
|||
use std::sync::mpsc::{Receiver, Sender};
|
||||
use style_traits::{CSSPixel, UnsafeNode};
|
||||
use webdriver_msg::{LoadStatus, WebDriverScriptCommand};
|
||||
use webvr_traits::{WebVRDisplayEvent, WebVRMsg};
|
||||
use webvr_traits::{WebVREvent, WebVRMsg};
|
||||
|
||||
pub use script_msg::{LayoutMsg, ScriptMsg, EventResult, LogEntry};
|
||||
pub use script_msg::{ServiceWorkerMsg, ScopeThings, SWManagerMsg, SWManagerSenders, DOMMessage};
|
||||
|
@ -280,8 +280,8 @@ pub enum ConstellationControlMsg {
|
|||
ReportCSSError(PipelineId, String, usize, usize, String),
|
||||
/// Reload the given page.
|
||||
Reload(PipelineId),
|
||||
/// Notifies the script thread of a WebVR device event
|
||||
WebVREvent(PipelineId, WebVREventMsg)
|
||||
/// Notifies the script thread of WebVR events.
|
||||
WebVREvents(PipelineId, Vec<WebVREvent>)
|
||||
}
|
||||
|
||||
impl fmt::Debug for ConstellationControlMsg {
|
||||
|
@ -314,7 +314,7 @@ impl fmt::Debug for ConstellationControlMsg {
|
|||
FramedContentChanged(..) => "FramedContentChanged",
|
||||
ReportCSSError(..) => "ReportCSSError",
|
||||
Reload(..) => "Reload",
|
||||
WebVREvent(..) => "WebVREvent",
|
||||
WebVREvents(..) => "WebVREvents",
|
||||
};
|
||||
write!(formatter, "ConstellationMsg::{}", variant)
|
||||
}
|
||||
|
@ -751,16 +751,8 @@ pub enum ConstellationMsg {
|
|||
LogEntry(Option<FrameId>, Option<String>, LogEntry),
|
||||
/// Set the WebVR thread channel.
|
||||
SetWebVRThread(IpcSender<WebVRMsg>),
|
||||
/// Dispatch a WebVR event to the subscribed script threads.
|
||||
WebVREvent(Vec<PipelineId>, WebVREventMsg),
|
||||
}
|
||||
|
||||
/// Messages to the constellation originating from the WebVR thread.
|
||||
/// Used to dispatch VR Headset state events: connected, unconnected, and more.
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
pub enum WebVREventMsg {
|
||||
/// Inform the constellation of a VR display event.
|
||||
DisplayEvent(WebVRDisplayEvent)
|
||||
/// Dispatch WebVR events to the subscribed script threads.
|
||||
WebVREvents(Vec<PipelineId>, Vec<WebVREvent>),
|
||||
}
|
||||
|
||||
/// Resources required by workerglobalscopes
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
use ipc_channel::ipc;
|
||||
use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use script_traits::{ConstellationMsg, WebVREventMsg};
|
||||
use script_traits::ConstellationMsg;
|
||||
use servo_config::prefs::PREFS;
|
||||
use std::{thread, time};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
@ -42,7 +42,7 @@ pub struct WebVRThread {
|
|||
constellation_chan: Sender<ConstellationMsg>,
|
||||
vr_compositor_chan: WebVRCompositorSender,
|
||||
polling_events: bool,
|
||||
presenting: HashMap<u64, PipelineId>
|
||||
presenting: HashMap<u32, PipelineId>
|
||||
}
|
||||
|
||||
impl WebVRThread {
|
||||
|
@ -108,6 +108,9 @@ impl WebVRThread {
|
|||
WebVRMsg::CreateCompositor(display_id) => {
|
||||
self.handle_create_compositor(display_id);
|
||||
},
|
||||
WebVRMsg::GetGamepads(synced_ids, sender) => {
|
||||
self.handle_get_gamepads(synced_ids, sender);
|
||||
}
|
||||
WebVRMsg::Exit => {
|
||||
break
|
||||
},
|
||||
|
@ -134,7 +137,7 @@ impl WebVRThread {
|
|||
|
||||
fn handle_framedata(&mut self,
|
||||
pipeline: PipelineId,
|
||||
display_id: u64,
|
||||
display_id: u32,
|
||||
near: f64,
|
||||
far: f64,
|
||||
sender: IpcSender<WebVRResult<VRFrameData>>) {
|
||||
|
@ -148,7 +151,7 @@ impl WebVRThread {
|
|||
|
||||
fn handle_reset_pose(&mut self,
|
||||
pipeline: PipelineId,
|
||||
display_id: u64,
|
||||
display_id: u32,
|
||||
sender: IpcSender<WebVRResult<VRDisplayData>>) {
|
||||
match self.access_check(pipeline, display_id) {
|
||||
Ok(display) => {
|
||||
|
@ -166,7 +169,7 @@ impl WebVRThread {
|
|||
// while the user is having a VR experience in the current tab.
|
||||
// These security rules also avoid multithreading race conditions between WebVRThread and
|
||||
// Webrender thread. See WebVRCompositorHandler implementation notes for more details about this.
|
||||
fn access_check(&self, pipeline: PipelineId, display_id: u64) -> Result<&VRDisplayPtr, &'static str> {
|
||||
fn access_check(&self, pipeline: PipelineId, display_id: u32) -> Result<&VRDisplayPtr, &'static str> {
|
||||
if *self.presenting.get(&display_id).unwrap_or(&pipeline) != pipeline {
|
||||
return Err("No access granted to this Display because it's presenting on other JavaScript Tab");
|
||||
}
|
||||
|
@ -175,14 +178,14 @@ impl WebVRThread {
|
|||
|
||||
fn handle_request_present(&mut self,
|
||||
pipeline: PipelineId,
|
||||
display_id: u64,
|
||||
display_id: u32,
|
||||
sender: IpcSender<WebVRResult<()>>) {
|
||||
match self.access_check(pipeline, display_id).map(|d| d.clone()) {
|
||||
Ok(display) => {
|
||||
self.presenting.insert(display_id, pipeline);
|
||||
let data = display.borrow().data();
|
||||
sender.send(Ok(())).unwrap();
|
||||
self.notify_event(VRDisplayEvent::PresentChange(data, true));
|
||||
self.notify_event(VRDisplayEvent::PresentChange(data, true).into());
|
||||
},
|
||||
Err(msg) => {
|
||||
sender.send(Err(msg.into())).unwrap();
|
||||
|
@ -192,7 +195,7 @@ impl WebVRThread {
|
|||
|
||||
fn handle_exit_present(&mut self,
|
||||
pipeline: PipelineId,
|
||||
display_id: u64,
|
||||
display_id: u32,
|
||||
sender: Option<IpcSender<WebVRResult<()>>>) {
|
||||
match self.access_check(pipeline, display_id).map(|d| d.clone()) {
|
||||
Ok(display) => {
|
||||
|
@ -201,7 +204,7 @@ impl WebVRThread {
|
|||
sender.send(Ok(())).unwrap();
|
||||
}
|
||||
let data = display.borrow().data();
|
||||
self.notify_event(VRDisplayEvent::PresentChange(data, false));
|
||||
self.notify_event(VRDisplayEvent::PresentChange(data, false).into());
|
||||
},
|
||||
Err(msg) => {
|
||||
if let Some(sender) = sender {
|
||||
|
@ -211,11 +214,28 @@ impl WebVRThread {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_create_compositor(&mut self, display_id: u64) {
|
||||
fn handle_create_compositor(&mut self, display_id: u32) {
|
||||
let compositor = self.service.get_display(display_id).map(|d| WebVRCompositor(d.as_ptr()));
|
||||
self.vr_compositor_chan.send(compositor).unwrap();
|
||||
}
|
||||
|
||||
fn handle_get_gamepads(&mut self,
|
||||
synced_ids: Vec<u32>,
|
||||
sender: IpcSender<WebVRResult<Vec<(Option<VRGamepadData>, VRGamepadState)>>>) {
|
||||
let gamepads = self.service.get_gamepads();
|
||||
let data = gamepads.iter().map(|g| {
|
||||
let g = g.borrow();
|
||||
// Optimization, don't fetch and send gamepad static data when the gamepad is already synced.
|
||||
let data = if synced_ids.iter().any(|v| *v == g.id()) {
|
||||
None
|
||||
} else {
|
||||
Some(g.data())
|
||||
};
|
||||
(data, g.state())
|
||||
}).collect();
|
||||
sender.send(Ok(data)).unwrap();
|
||||
}
|
||||
|
||||
fn poll_events(&mut self, sender: IpcSender<bool>) {
|
||||
loop {
|
||||
let events = self.service.poll_events();
|
||||
|
@ -230,16 +250,13 @@ impl WebVRThread {
|
|||
sender.send(self.polling_events).unwrap();
|
||||
}
|
||||
|
||||
fn notify_events(&self, events: Vec<VRDisplayEvent>) {
|
||||
fn notify_events(&self, events: Vec<VREvent>) {
|
||||
let pipeline_ids: Vec<PipelineId> = self.contexts.iter().map(|c| *c).collect();
|
||||
for event in events {
|
||||
let event = WebVREventMsg::DisplayEvent(event);
|
||||
self.constellation_chan.send(ConstellationMsg::WebVREvent(pipeline_ids.clone(), event)).unwrap();
|
||||
}
|
||||
self.constellation_chan.send(ConstellationMsg::WebVREvents(pipeline_ids.clone(), events)).unwrap();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn notify_event(&self, event: VRDisplayEvent) {
|
||||
fn notify_event(&self, event: VREvent) {
|
||||
self.notify_events(vec![event]);
|
||||
}
|
||||
|
||||
|
@ -334,7 +351,8 @@ impl webrender_traits::VRCompositorHandler for WebVRCompositorHandler {
|
|||
let layer = VRLayer {
|
||||
texture_id: texture_id,
|
||||
left_bounds: left_bounds,
|
||||
right_bounds: right_bounds
|
||||
right_bounds: right_bounds,
|
||||
texture_size: None
|
||||
};
|
||||
unsafe {
|
||||
(*compositor.0).submit_frame(&layer);
|
||||
|
@ -357,7 +375,7 @@ impl WebVRCompositorHandler {
|
|||
None => return,
|
||||
};
|
||||
|
||||
sender.send(WebVRMsg::CreateCompositor(display_id)).unwrap();
|
||||
sender.send(WebVRMsg::CreateCompositor(display_id as u32)).unwrap();
|
||||
let display = self.webvr_thread_receiver.recv().unwrap();
|
||||
|
||||
match display {
|
||||
|
|
|
@ -12,6 +12,6 @@ path = "lib.rs"
|
|||
[dependencies]
|
||||
ipc-channel = "0.7"
|
||||
msg = {path = "../msg"}
|
||||
rust-webvr = {version = "0.2", features = ["serde-serialization"]}
|
||||
rust-webvr = {version = "0.3", features = ["serde-serialization"]}
|
||||
serde = "0.9"
|
||||
serde_derive = "0.9"
|
||||
|
|
|
@ -16,9 +16,15 @@ pub use webvr::VRDisplayData as WebVRDisplayData;
|
|||
pub use webvr::VRDisplayCapabilities as WebVRDisplayCapabilities;
|
||||
pub use webvr::VRDisplayEvent as WebVRDisplayEvent;
|
||||
pub use webvr::VRDisplayEventReason as WebVRDisplayEventReason;
|
||||
pub use webvr::VREvent as WebVREvent;
|
||||
pub use webvr::VREye as WebVREye;
|
||||
pub use webvr::VREyeParameters as WebVREyeParameters;
|
||||
pub use webvr::VRFieldOfView as WebVRFieldOfView;
|
||||
pub use webvr::VRGamepadButton as WebVRGamepadButton;
|
||||
pub use webvr::VRGamepadData as WebVRGamepadData;
|
||||
pub use webvr::VRGamepadEvent as WebVRGamepadEvent;
|
||||
pub use webvr::VRGamepadHand as WebVRGamepadHand;
|
||||
pub use webvr::VRGamepadState as WebVRGamepadState;
|
||||
pub use webvr::VRFrameData as WebVRFrameData;
|
||||
pub use webvr::VRLayer as WebVRLayer;
|
||||
pub use webvr::VRPose as WebVRPose;
|
||||
|
|
|
@ -15,10 +15,11 @@ pub enum WebVRMsg {
|
|||
UnregisterContext(PipelineId),
|
||||
PollEvents(IpcSender<bool>),
|
||||
GetDisplays(IpcSender<WebVRResult<Vec<VRDisplayData>>>),
|
||||
GetFrameData(PipelineId, u64, f64, f64, IpcSender<WebVRResult<VRFrameData>>),
|
||||
ResetPose(PipelineId, u64, IpcSender<WebVRResult<VRDisplayData>>),
|
||||
RequestPresent(PipelineId, u64, IpcSender<WebVRResult<()>>),
|
||||
ExitPresent(PipelineId, u64, Option<IpcSender<WebVRResult<()>>>),
|
||||
CreateCompositor(u64),
|
||||
GetFrameData(PipelineId, u32, f64, f64, IpcSender<WebVRResult<VRFrameData>>),
|
||||
ResetPose(PipelineId, u32, IpcSender<WebVRResult<VRDisplayData>>),
|
||||
RequestPresent(PipelineId, u32, IpcSender<WebVRResult<()>>),
|
||||
ExitPresent(PipelineId, u32, Option<IpcSender<WebVRResult<()>>>),
|
||||
CreateCompositor(u32),
|
||||
GetGamepads(Vec<u32>, IpcSender<WebVRResult<Vec<(Option<VRGamepadData>, VRGamepadState)>>>),
|
||||
Exit,
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue