Auto merge of #13130 - samuknet:dblclick, r=nox

'dblclick' event

<!-- Please describe your changes on the following line: -->
* Add field to document struct to store information about last 'click' event
* Add code to `handle_mouse_event` function to detect and fire double click events

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [ X] `./mach build -d` does not report any errors
- [X ] `./mach test-tidy` does not report any errors
- [X ] These changes fix #12767  (github issue number if applicable).

<!-- Either: -->
- [ ] There are tests for these changes OR
- [X ] These changes do not require tests because it is input related

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/13130)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-09-10 08:46:13 -05:00 committed by GitHub
commit 67bfd0df4b
2 changed files with 59 additions and 1 deletions

View file

@ -87,7 +87,7 @@ use std::rc::Rc;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicUsize};
use std::sync::mpsc::{Receiver, Sender};
use std::time::SystemTime;
use std::time::{SystemTime, Instant};
use string_cache::{Atom, Namespace, QualName};
use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto};
use style::domrefcell::DOMRefCell;
@ -346,6 +346,7 @@ no_jsmanaged_fields!(ResponseBody);
no_jsmanaged_fields!(ResourceThreads);
no_jsmanaged_fields!(StatusCode);
no_jsmanaged_fields!(SystemTime);
no_jsmanaged_fields!(Instant);
no_jsmanaged_fields!(RelativePos);
no_jsmanaged_fields!(OpaqueStyleAndLayoutData);
no_jsmanaged_fields!(PathBuf);

View file

@ -119,6 +119,7 @@ use std::iter::once;
use std::mem;
use std::rc::Rc;
use std::sync::Arc;
use std::time::{Duration, Instant};
use string_cache::{Atom, QualName};
use style::attr::AttrValue;
use style::context::ReflowGoal;
@ -247,6 +248,9 @@ pub struct Document {
referrer: Option<String>,
/// https://html.spec.whatwg.org/multipage/#target-element
target_element: MutNullableHeap<JS<Element>>,
/// https://w3c.github.io/uievents/#event-type-dblclick
#[ignore_heap_size_of = "Defined in std"]
last_click_info: DOMRefCell<Option<(Instant, Point2D<f32>)>>,
}
#[derive(JSTraceable, HeapSizeOf)]
@ -774,12 +778,64 @@ impl Document {
if let MouseEventType::Click = mouse_event_type {
self.commit_focus_transaction(FocusType::Element);
self.maybe_fire_dblclick(client_point, node);
}
self.window.reflow(ReflowGoal::ForDisplay,
ReflowQueryType::NoQuery,
ReflowReason::MouseEvent);
}
fn maybe_fire_dblclick(&self, click_pos: Point2D<f32>, target: &Node) {
// https://w3c.github.io/uievents/#event-type-dblclick
let now = Instant::now();
let opt = self.last_click_info.borrow_mut().take();
if let Some((last_time, last_pos)) = opt {
let DBL_CLICK_TIMEOUT = Duration::from_millis(PREFS.get("dom.document.dblclick_timeout").as_u64()
.unwrap_or(300));
let DBL_CLICK_DIST_THRESHOLD = PREFS.get("dom.document.dblclick_dist").as_u64().unwrap_or(1);
// Calculate distance between this click and the previous click.
let line = click_pos - last_pos;
let dist = (line.dot(line) as f64).sqrt();
if now.duration_since(last_time) < DBL_CLICK_TIMEOUT &&
dist < DBL_CLICK_DIST_THRESHOLD as f64 {
// A double click has occurred if this click is within a certain time and dist. of previous click.
let clickCount = 2;
let client_x = click_pos.x as i32;
let client_y = click_pos.y as i32;
let event = MouseEvent::new(&self.window,
DOMString::from("dblclick"),
EventBubbles::Bubbles,
EventCancelable::Cancelable,
Some(&self.window),
clickCount,
client_x,
client_y,
client_x,
client_y,
false,
false,
false,
false,
0i16,
None);
event.upcast::<Event>().fire(target.upcast());
// When a double click occurs, self.last_click_info is left as None so that a
// third sequential click will not cause another double click.
return;
}
}
// Update last_click_info with the time and position of the click.
*self.last_click_info.borrow_mut() = Some((now, click_pos));
}
pub fn handle_touchpad_pressure_event(&self,
js_runtime: *mut JSRuntime,
client_point: Point2D<f32>,
@ -1759,6 +1815,7 @@ impl Document {
referrer: referrer,
referrer_policy: Cell::new(referrer_policy),
target_element: MutNullableHeap::new(None),
last_click_info: DOMRefCell::new(None),
}
}