diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/bindings/trace.rs | 3 | ||||
-rw-r--r-- | components/script/dom/document.rs | 69 | ||||
-rw-r--r-- | components/script/dom/forcetouchevent.rs | 59 | ||||
-rw-r--r-- | components/script/dom/mod.rs | 1 | ||||
-rw-r--r-- | components/script/dom/webidls/ForceTouchEvent.webidl | 35 | ||||
-rw-r--r-- | components/script/script_thread.rs | 8 |
6 files changed, 172 insertions, 3 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 2491058750c..a23a5452f1c 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -64,7 +64,7 @@ use net_traits::storage_thread::StorageType; use profile_traits::mem::ProfilerChan as MemProfilerChan; use profile_traits::time::ProfilerChan as TimeProfilerChan; use script_thread::ScriptChan; -use script_traits::{LayoutMsg, ScriptMsg, TimerEventId, TimerSource, UntrustedNodeAddress}; +use script_traits::{LayoutMsg, ScriptMsg, TimerEventId, TimerSource, TouchpadPressurePhase, UntrustedNodeAddress}; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; use std::boxed::FnBox; @@ -319,6 +319,7 @@ no_jsmanaged_fields!(AttrIdentifier); no_jsmanaged_fields!(AttrValue); no_jsmanaged_fields!(ElementSnapshot); no_jsmanaged_fields!(HttpsState); +no_jsmanaged_fields!(TouchpadPressurePhase); impl JSTraceable for ConstellationChan<ScriptMsg> { #[inline] diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 703a7c90572..c99099e04f9 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -41,6 +41,7 @@ use dom::element::{Element, ElementCreator}; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::eventtarget::EventTarget; use dom::focusevent::FocusEvent; +use dom::forcetouchevent::ForceTouchEvent; use dom::htmlanchorelement::HTMLAnchorElement; use dom::htmlappletelement::HTMLAppletElement; use dom::htmlareaelement::HTMLAreaElement; @@ -97,7 +98,7 @@ use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, Runnable, ScriptC use script_traits::UntrustedNodeAddress; use script_traits::{AnimationState, MouseButton, MouseEventType, MozBrowserEvent}; use script_traits::{ScriptMsg as ConstellationMsg, ScriptToCompositorMsg}; -use script_traits::{TouchEventType, TouchId}; +use script_traits::{TouchpadPressurePhase, TouchEventType, TouchId}; use std::ascii::AsciiExt; use std::borrow::ToOwned; use std::boxed::FnBox; @@ -218,6 +219,7 @@ pub struct Document { css_errors_store: DOMRefCell<Vec<CSSError>>, /// https://html.spec.whatwg.org/multipage/#concept-document-https-state https_state: Cell<HttpsState>, + touchpad_pressure_phase: Cell<TouchpadPressurePhase>, } #[derive(JSTraceable, HeapSizeOf)] @@ -732,6 +734,70 @@ impl Document { ReflowReason::MouseEvent); } + pub fn handle_touchpad_pressure_event(&self, + js_runtime: *mut JSRuntime, + client_point: Point2D<f32>, + pressure: f32, + phase_now: TouchpadPressurePhase) { + + let phase_before = self.touchpad_pressure_phase.get(); + self.touchpad_pressure_phase.set(phase_now); + + if phase_before == TouchpadPressurePhase::BeforeClick && + phase_now == TouchpadPressurePhase::BeforeClick { + return; + } + + let page_point = Point2D::new(client_point.x + self.window.PageXOffset() as f32, + client_point.y + self.window.PageYOffset() as f32); + let node = match self.window.hit_test_query(page_point, false) { + Some(node_address) => node::from_untrusted_node_address(js_runtime, node_address), + None => return + }; + + let el = match node.downcast::<Element>() { + Some(el) => Root::from_ref(el), + None => { + let parent = node.GetParentNode(); + match parent.and_then(Root::downcast::<Element>) { + Some(parent) => parent, + None => return + } + }, + }; + + let node = el.upcast::<Node>(); + let target = node.upcast(); + + let force = match phase_now { + TouchpadPressurePhase::BeforeClick => pressure, + TouchpadPressurePhase::AfterFirstClick => 1. + pressure, + TouchpadPressurePhase::AfterSecondClick => 2. + pressure, + }; + + if phase_now != TouchpadPressurePhase::BeforeClick { + self.fire_forcetouch_event("servomouseforcechanged".to_owned(), target, force); + } + + if phase_before != TouchpadPressurePhase::AfterSecondClick && + phase_now == TouchpadPressurePhase::AfterSecondClick { + self.fire_forcetouch_event("servomouseforcedown".to_owned(), target, force); + } + + if phase_before == TouchpadPressurePhase::AfterSecondClick && + phase_now != TouchpadPressurePhase::AfterSecondClick { + self.fire_forcetouch_event("servomouseforceup".to_owned(), target, force); + } + } + + fn fire_forcetouch_event(&self, event_name: String, target: &EventTarget, force: f32) { + let force_event = ForceTouchEvent::new(&self.window, + DOMString::from(event_name), + force); + let event = force_event.upcast::<Event>(); + event.fire(target); + } + pub fn fire_mouse_event(&self, client_point: Point2D<f32>, target: &EventTarget, event_name: String) { let client_x = client_point.x.to_i32().unwrap_or(0); let client_y = client_point.y.to_i32().unwrap_or(0); @@ -1593,6 +1659,7 @@ impl Document { dom_complete: Cell::new(Default::default()), css_errors_store: DOMRefCell::new(vec![]), https_state: Cell::new(HttpsState::None), + touchpad_pressure_phase: Cell::new(TouchpadPressurePhase::BeforeClick), } } diff --git a/components/script/dom/forcetouchevent.rs b/components/script/dom/forcetouchevent.rs new file mode 100644 index 00000000000..b0fd6376760 --- /dev/null +++ b/components/script/dom/forcetouchevent.rs @@ -0,0 +1,59 @@ +/* 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::ForceTouchEventBinding; +use dom::bindings::codegen::Bindings::ForceTouchEventBinding::ForceTouchEventMethods; +use dom::bindings::codegen::Bindings::UIEventBinding::UIEventMethods; +use dom::bindings::global::GlobalRef; +use dom::bindings::inheritance::Castable; +use dom::bindings::js::{Root}; +use dom::bindings::num::Finite; +use dom::bindings::reflector::reflect_dom_object; +use dom::uievent::UIEvent; +use dom::window::Window; +use util::str::DOMString; + +#[dom_struct] +pub struct ForceTouchEvent { + uievent: UIEvent, + force: f32, +} + +impl ForceTouchEvent { + fn new_inherited(force: f32) -> ForceTouchEvent { + ForceTouchEvent { + uievent: UIEvent::new_inherited(), + force: force, + } + } + + pub fn new(window: &Window, + type_: DOMString, + force: f32) -> Root<ForceTouchEvent> { + let event = box ForceTouchEvent::new_inherited(force); + let ev = reflect_dom_object(event, GlobalRef::Window(window), ForceTouchEventBinding::Wrap); + ev.upcast::<UIEvent>().InitUIEvent(type_, true, true, Some(window), 0); + ev + } +} + +impl<'a> ForceTouchEventMethods for &'a ForceTouchEvent { + + fn ServoForce(&self) -> Finite<f32> { + Finite::wrap(self.force) + } + + fn SERVO_FORCE_AT_MOUSE_DOWN(&self) -> Finite<f32> { + Finite::wrap(1.0) + } + + fn SERVO_FORCE_AT_FORCE_MOUSE_DOWN(&self) -> Finite<f32> { + Finite::wrap(2.0) + } + + // https://dom.spec.whatwg.org/#dom-event-istrusted + fn IsTrusted(&self) -> bool { + self.uievent.IsTrusted() + } +} diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 662f41dc7a9..36921d8be89 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -264,6 +264,7 @@ pub mod file; pub mod filelist; pub mod filereader; pub mod focusevent; +pub mod forcetouchevent; pub mod formdata; pub mod htmlanchorelement; pub mod htmlappletelement; diff --git a/components/script/dom/webidls/ForceTouchEvent.webidl b/components/script/dom/webidls/ForceTouchEvent.webidl new file mode 100644 index 00000000000..a5f8ceef9a4 --- /dev/null +++ b/components/script/dom/webidls/ForceTouchEvent.webidl @@ -0,0 +1,35 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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://developer.apple.com/library/mac/documentation/AppleApplications/Conceptual/SafariJSProgTopics/RespondingtoForceTouchEventsfromJavaScript.html + +/** + * Events: (copy/paste from apple.com) + * + * webkitmouseforcewillbegin: This event occurs immediately before the mousedown event. It allows you to + * prevent the default system behavior, such as displaying a dictionary window when force clicking on a + * word, in order to perform a custom action instead. To prevent the default system behavior, call the + * preventDefault() method on the event. + * webkitmouseforcedown: This event occurs after the mousedown event, once enough force has been applied + * to register as a force click. The user receives haptic feedback representing the force click when this + * event occurs. + * webkitmouseforceup: This event occurs after a webkitmouseforcedown event, once enough force has been + * released to exit the force click operation. The user receives haptic feedback representing the exit + * from force click when this event occurs. + * webkitmouseforcechanged: This event occurs whenever a change in trackpad force is detected between the + * mousedown and mouseup events. + * + */ + + +[Pref="dom.forcetouch.enabled"] +interface ForceTouchEvent : UIEvent { + // Represents the amount of force required to perform a regular click. + readonly attribute float SERVO_FORCE_AT_MOUSE_DOWN; + // Represents the force required to perform a force click. + readonly attribute float SERVO_FORCE_AT_FORCE_MOUSE_DOWN; + // force level + readonly attribute float servoForce; +}; diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 5cd38e80532..6726a6ca4e2 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -79,7 +79,7 @@ use parse::xml::{self, parse_xml}; use profile_traits::mem::{self, OpaqueSender, Report, ReportKind, ReportsChan}; use profile_traits::time::{self, ProfilerCategory, profile}; use script_traits::CompositorEvent::{KeyEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent}; -use script_traits::CompositorEvent::{TouchEvent}; +use script_traits::CompositorEvent::{TouchEvent, TouchpadPressureEvent}; use script_traits::{CompositorEvent, ConstellationControlMsg, EventResult}; use script_traits::{InitialScriptState, MouseButton, MouseEventType, MozBrowserEvent, NewLayoutInfo}; use script_traits::{LayoutMsg, OpaqueScriptLayoutChannel, ScriptMsg as ConstellationMsg}; @@ -1969,6 +1969,12 @@ impl ScriptThread { } } + TouchpadPressureEvent(point, pressure, phase) => { + let page = get_page(&self.root_page(), pipeline_id); + let document = page.document(); + document.r().handle_touchpad_pressure_event(self.js_runtime.rt(), point, pressure, phase); + } + KeyEvent(key, state, modifiers) => { let page = get_page(&self.root_page(), pipeline_id); let document = page.document(); |