Implement home end key scroll.

This commit is contained in:
Sam 2016-11-08 18:00:43 +00:00
parent ca6376a714
commit 7e4255eb95
9 changed files with 118 additions and 47 deletions

View file

@ -39,7 +39,7 @@ use style_traits::viewport::ViewportConstraints;
use time::{precise_time_ns, precise_time_s};
use touch::{TouchHandler, TouchAction};
use webrender;
use webrender_traits::{self, ScrollEventPhase, ServoScrollRootId, LayoutPoint};
use webrender_traits::{self, ScrollEventPhase, ServoScrollRootId, LayoutPoint, ScrollLocation};
use windowing::{self, MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg};
#[derive(Debug, PartialEq)]
@ -227,8 +227,8 @@ pub struct IOCompositor<Window: WindowMethods> {
struct ScrollZoomEvent {
/// Change the pinch zoom level by this factor
magnification: f32,
/// Scroll by this offset
delta: TypedPoint2D<f32, DevicePixel>,
/// Scroll by this offset, or to Start or End
scroll_location: ScrollLocation,
/// Apply changes to the frame at this location
cursor: TypedPoint2D<i32, DevicePixel>,
/// The scroll event phase.
@ -1037,7 +1037,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
match self.touch_handler.on_touch_move(identifier, point) {
TouchAction::Scroll(delta) => {
match point.cast() {
Some(point) => self.on_scroll_window_event(delta, point),
Some(point) => self.on_scroll_window_event(ScrollLocation::Delta(
webrender_traits::LayerPoint::from_untyped(
&delta.to_untyped())),
point),
None => error!("Point cast failed."),
}
}
@ -1045,7 +1048,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
let cursor = TypedPoint2D::new(-1, -1); // Make sure this hits the base layer.
self.pending_scroll_zoom_events.push(ScrollZoomEvent {
magnification: magnification,
delta: scroll_delta,
scroll_location: ScrollLocation::Delta(webrender_traits::LayerPoint::from_untyped(
&scroll_delta.to_untyped())),
cursor: cursor,
phase: ScrollEventPhase::Move(true),
event_count: 1,
@ -1106,7 +1110,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
fn on_scroll_window_event(&mut self,
delta: TypedPoint2D<f32, DevicePixel>,
scroll_location: ScrollLocation,
cursor: TypedPoint2D<i32, DevicePixel>) {
let event_phase = match (self.scroll_in_progress, self.in_scroll_transaction) {
(false, None) => ScrollEventPhase::Start,
@ -1117,7 +1121,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.in_scroll_transaction = Some(Instant::now());
self.pending_scroll_zoom_events.push(ScrollZoomEvent {
magnification: 1.0,
delta: delta,
scroll_location: scroll_location,
cursor: cursor,
phase: event_phase,
event_count: 1,
@ -1125,12 +1129,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
fn on_scroll_start_window_event(&mut self,
delta: TypedPoint2D<f32, DevicePixel>,
scroll_location: ScrollLocation,
cursor: TypedPoint2D<i32, DevicePixel>) {
self.scroll_in_progress = true;
self.pending_scroll_zoom_events.push(ScrollZoomEvent {
magnification: 1.0,
delta: delta,
scroll_location: scroll_location,
cursor: cursor,
phase: ScrollEventPhase::Start,
event_count: 1,
@ -1138,12 +1142,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
fn on_scroll_end_window_event(&mut self,
delta: TypedPoint2D<f32, DevicePixel>,
scroll_location: ScrollLocation,
cursor: TypedPoint2D<i32, DevicePixel>) {
self.scroll_in_progress = false;
self.pending_scroll_zoom_events.push(ScrollZoomEvent {
magnification: 1.0,
delta: delta,
scroll_location: scroll_location,
cursor: cursor,
phase: ScrollEventPhase::End,
event_count: 1,
@ -1156,14 +1160,34 @@ impl<Window: WindowMethods> IOCompositor<Window> {
// Batch up all scroll events into one, or else we'll do way too much painting.
let mut last_combined_event: Option<ScrollZoomEvent> = None;
for scroll_event in self.pending_scroll_zoom_events.drain(..) {
let this_delta = scroll_event.delta;
let this_cursor = scroll_event.cursor;
let this_delta = match scroll_event.scroll_location {
ScrollLocation::Delta(delta) => delta,
ScrollLocation::Start | ScrollLocation::End => {
// If this is an event which is scrolling to the start or end of the page,
// disregard other pending events and exit the loop.
last_combined_event = Some(scroll_event);
break;
}
};
if let Some(combined_event) = last_combined_event {
if combined_event.phase != scroll_event.phase {
let delta = (combined_event.delta / self.scale).to_untyped();
let combined_delta = match combined_event.scroll_location {
ScrollLocation::Delta(delta) => delta,
ScrollLocation::Start | ScrollLocation::End => {
// If this is an event which is scrolling to the start or end of the page,
// disregard other pending events and exit the loop.
last_combined_event = Some(scroll_event);
break;
}
};
let delta = (TypedPoint2D::from_untyped(&combined_delta.to_untyped()) / self.scale)
.to_untyped();
let delta = webrender_traits::LayerPoint::from_untyped(&delta);
let cursor =
(combined_event.cursor.to_f32() / self.scale).to_untyped();
let delta = webrender_traits::LayerPoint::from_untyped(&delta);
let location = webrender_traits::ScrollLocation::Delta(delta);
let cursor = webrender_traits::WorldPoint::from_untyped(&cursor);
self.webrender_api.scroll(location, cursor, combined_event.phase);
@ -1175,7 +1199,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
(last_combined_event @ &mut None, _) => {
*last_combined_event = Some(ScrollZoomEvent {
magnification: scroll_event.magnification,
delta: this_delta,
scroll_location: ScrollLocation::Delta(webrender_traits::LayerPoint::from_untyped(
&this_delta.to_untyped())),
cursor: this_cursor,
phase: scroll_event.phase,
event_count: 1,
@ -1187,30 +1212,41 @@ impl<Window: WindowMethods> IOCompositor<Window> {
// fling. This causes events to get bunched up occasionally, causing
// nasty-looking "pops". To mitigate this, during a fling we average
// deltas instead of summing them.
let old_event_count =
ScaleFactor::new(last_combined_event.event_count as f32);
last_combined_event.event_count += 1;
let new_event_count =
ScaleFactor::new(last_combined_event.event_count as f32);
last_combined_event.delta =
(last_combined_event.delta * old_event_count + this_delta) /
new_event_count;
if let ScrollLocation::Delta(delta) = last_combined_event.scroll_location {
let old_event_count =
ScaleFactor::new(last_combined_event.event_count as f32);
last_combined_event.event_count += 1;
let new_event_count =
ScaleFactor::new(last_combined_event.event_count as f32);
last_combined_event.scroll_location = ScrollLocation::Delta(
(delta * old_event_count + this_delta) /
new_event_count);
}
}
(&mut Some(ref mut last_combined_event), _) => {
last_combined_event.delta = last_combined_event.delta + this_delta;
last_combined_event.event_count += 1
if let ScrollLocation::Delta(delta) = last_combined_event.scroll_location {
last_combined_event.scroll_location = ScrollLocation::Delta(delta + this_delta);
last_combined_event.event_count += 1
}
}
}
}
// TODO(gw): Support zoom (WR issue #28).
if let Some(combined_event) = last_combined_event {
let delta = (combined_event.delta / self.scale).to_untyped();
let delta = webrender_traits::LayoutPoint::from_untyped(&delta);
let scroll_location = match combined_event.scroll_location {
ScrollLocation::Delta(delta) => {
let scaled_delta = (TypedPoint2D::from_untyped(&delta.to_untyped()) / self.scale)
.to_untyped();
let calculated_delta = webrender_traits::LayoutPoint::from_untyped(&scaled_delta);
ScrollLocation::Delta(calculated_delta)
},
// Leave ScrollLocation unchanged if it is Start or End location.
sl @ ScrollLocation::Start | sl @ ScrollLocation::End => sl,
};
let cursor = (combined_event.cursor.to_f32() / self.scale).to_untyped();
let location = webrender_traits::ScrollLocation::Delta(delta);
let cursor = webrender_traits::WorldPoint::from_untyped(&cursor);
self.webrender_api.scroll(location, cursor, combined_event.phase);
self.webrender_api.scroll(scroll_location, cursor, combined_event.phase);
self.waiting_for_results_of_scroll = true
}
@ -1305,7 +1341,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
fn on_pinch_zoom_window_event(&mut self, magnification: f32) {
self.pending_scroll_zoom_events.push(ScrollZoomEvent {
magnification: magnification,
delta: TypedPoint2D::zero(), // TODO: Scroll to keep the center in view?
scroll_location: ScrollLocation::Delta(TypedPoint2D::zero()), // TODO: Scroll to keep the center in view?
cursor: TypedPoint2D::new(-1, -1), // Make sure this hits the base layer.
phase: ScrollEventPhase::Move(true),
event_count: 1,
@ -1703,6 +1739,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
}
/// Why we performed a composite. This is used for debugging.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum CompositingReason {

View file

@ -16,6 +16,7 @@ use servo_geometry::ScreenPx;
use servo_url::ServoUrl;
use std::fmt::{Debug, Error, Formatter};
use style_traits::cursor::Cursor;
use webrender_traits::ScrollLocation;
#[derive(Clone)]
pub enum MouseWindowEvent {
@ -62,7 +63,7 @@ pub enum WindowEvent {
Touch(TouchEventType, TouchId, TypedPoint2D<f32, DevicePixel>),
/// Sent when the user scrolls. The first point is the delta and the second point is the
/// origin.
Scroll(TypedPoint2D<f32, DevicePixel>, TypedPoint2D<i32, DevicePixel>, TouchEventType),
Scroll(ScrollLocation, TypedPoint2D<i32, DevicePixel>, TouchEventType),
/// Sent when the user zooms.
Zoom(f32),
/// Simulated "pinch zoom" gesture for non-touch platforms (e.g. ctrl-scrollwheel).