mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Auto merge of #14141 - samuknet:home-end-key-scroll2, r=glennw
Implement home end key scrolling <!-- Please describe your changes on the following line: --> * Refactor all scroll related code to use a new `ScrollLocation` struct which can either be a `delta` (as before) or a `Start` or `End` request, to represent the desire to scroll to the start and end of the page. Effectively, everywhere a delta was used, there is now a `ScrollLocation` struct instead. * Add key press listeners for HOME and END keys so as to cause a scroll to be queued with `ScrollLocation::Start` (in HOME case) or `ScrollLocation::End` (in END case). * These changes depend on added support for the new `ScrollLocation` in webrender and webrender_traits. See https://github.com/servo/webrender/pull/540. --- <!-- 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 #13082 (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [x] These changes do not require tests because scrolling I/O <!-- 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/14141) <!-- Reviewable:end -->
This commit is contained in:
commit
1706ffd6e5
9 changed files with 118 additions and 47 deletions
|
@ -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.
|
||||
|
@ -1027,7 +1027,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."),
|
||||
}
|
||||
}
|
||||
|
@ -1035,7 +1038,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,
|
||||
|
@ -1096,7 +1100,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,
|
||||
|
@ -1107,7 +1111,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,
|
||||
|
@ -1115,12 +1119,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,
|
||||
|
@ -1128,12 +1132,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,
|
||||
|
@ -1146,14 +1150,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);
|
||||
|
@ -1165,7 +1189,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,
|
||||
|
@ -1177,30 +1202,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
|
||||
}
|
||||
|
||||
|
@ -1295,7 +1331,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,
|
||||
|
@ -1693,6 +1729,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// Why we performed a composite. This is used for debugging.
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum CompositingReason {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue