Skip to content

Commit 3535d5b

Browse files
author
bors-servo
authored
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 servo/webrender#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 -->
2 parents ca6376a + 0c9c343 commit 3535d5b

File tree

6 files changed

+109
-46
lines changed

6 files changed

+109
-46
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/compositing/compositor.rs

Lines changed: 67 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ use style_traits::viewport::ViewportConstraints;
3939
use time::{precise_time_ns, precise_time_s};
4040
use touch::{TouchHandler, TouchAction};
4141
use webrender;
42-
use webrender_traits::{self, ScrollEventPhase, ServoScrollRootId, LayoutPoint};
42+
use webrender_traits::{self, ScrollEventPhase, ServoScrollRootId, LayoutPoint, ScrollLocation};
4343
use windowing::{self, MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg};
4444

4545
#[derive(Debug, PartialEq)]
@@ -227,8 +227,8 @@ pub struct IOCompositor<Window: WindowMethods> {
227227
struct ScrollZoomEvent {
228228
/// Change the pinch zoom level by this factor
229229
magnification: f32,
230-
/// Scroll by this offset
231-
delta: TypedPoint2D<f32, DevicePixel>,
230+
/// Scroll by this offset, or to Start or End
231+
scroll_location: ScrollLocation,
232232
/// Apply changes to the frame at this location
233233
cursor: TypedPoint2D<i32, DevicePixel>,
234234
/// The scroll event phase.
@@ -1037,15 +1037,19 @@ impl<Window: WindowMethods> IOCompositor<Window> {
10371037
match self.touch_handler.on_touch_move(identifier, point) {
10381038
TouchAction::Scroll(delta) => {
10391039
match point.cast() {
1040-
Some(point) => self.on_scroll_window_event(delta, point),
1040+
Some(point) => self.on_scroll_window_event(ScrollLocation::Delta(
1041+
webrender_traits::LayerPoint::from_untyped(
1042+
&delta.to_untyped())),
1043+
point),
10411044
None => error!("Point cast failed."),
10421045
}
10431046
}
10441047
TouchAction::Zoom(magnification, scroll_delta) => {
10451048
let cursor = TypedPoint2D::new(-1, -1); // Make sure this hits the base layer.
10461049
self.pending_scroll_zoom_events.push(ScrollZoomEvent {
10471050
magnification: magnification,
1048-
delta: scroll_delta,
1051+
scroll_location: ScrollLocation::Delta(webrender_traits::LayerPoint::from_untyped(
1052+
&scroll_delta.to_untyped())),
10491053
cursor: cursor,
10501054
phase: ScrollEventPhase::Move(true),
10511055
event_count: 1,
@@ -1106,7 +1110,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
11061110
}
11071111

11081112
fn on_scroll_window_event(&mut self,
1109-
delta: TypedPoint2D<f32, DevicePixel>,
1113+
scroll_location: ScrollLocation,
11101114
cursor: TypedPoint2D<i32, DevicePixel>) {
11111115
let event_phase = match (self.scroll_in_progress, self.in_scroll_transaction) {
11121116
(false, None) => ScrollEventPhase::Start,
@@ -1117,33 +1121,33 @@ impl<Window: WindowMethods> IOCompositor<Window> {
11171121
self.in_scroll_transaction = Some(Instant::now());
11181122
self.pending_scroll_zoom_events.push(ScrollZoomEvent {
11191123
magnification: 1.0,
1120-
delta: delta,
1124+
scroll_location: scroll_location,
11211125
cursor: cursor,
11221126
phase: event_phase,
11231127
event_count: 1,
11241128
});
11251129
}
11261130

11271131
fn on_scroll_start_window_event(&mut self,
1128-
delta: TypedPoint2D<f32, DevicePixel>,
1132+
scroll_location: ScrollLocation,
11291133
cursor: TypedPoint2D<i32, DevicePixel>) {
11301134
self.scroll_in_progress = true;
11311135
self.pending_scroll_zoom_events.push(ScrollZoomEvent {
11321136
magnification: 1.0,
1133-
delta: delta,
1137+
scroll_location: scroll_location,
11341138
cursor: cursor,
11351139
phase: ScrollEventPhase::Start,
11361140
event_count: 1,
11371141
});
11381142
}
11391143

11401144
fn on_scroll_end_window_event(&mut self,
1141-
delta: TypedPoint2D<f32, DevicePixel>,
1145+
scroll_location: ScrollLocation,
11421146
cursor: TypedPoint2D<i32, DevicePixel>) {
11431147
self.scroll_in_progress = false;
11441148
self.pending_scroll_zoom_events.push(ScrollZoomEvent {
11451149
magnification: 1.0,
1146-
delta: delta,
1150+
scroll_location: scroll_location,
11471151
cursor: cursor,
11481152
phase: ScrollEventPhase::End,
11491153
event_count: 1,
@@ -1156,14 +1160,34 @@ impl<Window: WindowMethods> IOCompositor<Window> {
11561160
// Batch up all scroll events into one, or else we'll do way too much painting.
11571161
let mut last_combined_event: Option<ScrollZoomEvent> = None;
11581162
for scroll_event in self.pending_scroll_zoom_events.drain(..) {
1159-
let this_delta = scroll_event.delta;
11601163
let this_cursor = scroll_event.cursor;
1164+
1165+
let this_delta = match scroll_event.scroll_location {
1166+
ScrollLocation::Delta(delta) => delta,
1167+
ScrollLocation::Start | ScrollLocation::End => {
1168+
// If this is an event which is scrolling to the start or end of the page,
1169+
// disregard other pending events and exit the loop.
1170+
last_combined_event = Some(scroll_event);
1171+
break;
1172+
}
1173+
};
1174+
11611175
if let Some(combined_event) = last_combined_event {
11621176
if combined_event.phase != scroll_event.phase {
1163-
let delta = (combined_event.delta / self.scale).to_untyped();
1177+
let combined_delta = match combined_event.scroll_location {
1178+
ScrollLocation::Delta(delta) => delta,
1179+
ScrollLocation::Start | ScrollLocation::End => {
1180+
// If this is an event which is scrolling to the start or end of the page,
1181+
// disregard other pending events and exit the loop.
1182+
last_combined_event = Some(scroll_event);
1183+
break;
1184+
}
1185+
};
1186+
let delta = (TypedPoint2D::from_untyped(&combined_delta.to_untyped()) / self.scale)
1187+
.to_untyped();
1188+
let delta = webrender_traits::LayerPoint::from_untyped(&delta);
11641189
let cursor =
11651190
(combined_event.cursor.to_f32() / self.scale).to_untyped();
1166-
let delta = webrender_traits::LayerPoint::from_untyped(&delta);
11671191
let location = webrender_traits::ScrollLocation::Delta(delta);
11681192
let cursor = webrender_traits::WorldPoint::from_untyped(&cursor);
11691193
self.webrender_api.scroll(location, cursor, combined_event.phase);
@@ -1175,7 +1199,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
11751199
(last_combined_event @ &mut None, _) => {
11761200
*last_combined_event = Some(ScrollZoomEvent {
11771201
magnification: scroll_event.magnification,
1178-
delta: this_delta,
1202+
scroll_location: ScrollLocation::Delta(webrender_traits::LayerPoint::from_untyped(
1203+
&this_delta.to_untyped())),
11791204
cursor: this_cursor,
11801205
phase: scroll_event.phase,
11811206
event_count: 1,
@@ -1187,30 +1212,41 @@ impl<Window: WindowMethods> IOCompositor<Window> {
11871212
// fling. This causes events to get bunched up occasionally, causing
11881213
// nasty-looking "pops". To mitigate this, during a fling we average
11891214
// deltas instead of summing them.
1190-
let old_event_count =
1191-
ScaleFactor::new(last_combined_event.event_count as f32);
1192-
last_combined_event.event_count += 1;
1193-
let new_event_count =
1194-
ScaleFactor::new(last_combined_event.event_count as f32);
1195-
last_combined_event.delta =
1196-
(last_combined_event.delta * old_event_count + this_delta) /
1197-
new_event_count;
1215+
if let ScrollLocation::Delta(delta) = last_combined_event.scroll_location {
1216+
let old_event_count =
1217+
ScaleFactor::new(last_combined_event.event_count as f32);
1218+
last_combined_event.event_count += 1;
1219+
let new_event_count =
1220+
ScaleFactor::new(last_combined_event.event_count as f32);
1221+
last_combined_event.scroll_location = ScrollLocation::Delta(
1222+
(delta * old_event_count + this_delta) /
1223+
new_event_count);
1224+
}
11981225
}
11991226
(&mut Some(ref mut last_combined_event), _) => {
1200-
last_combined_event.delta = last_combined_event.delta + this_delta;
1201-
last_combined_event.event_count += 1
1227+
if let ScrollLocation::Delta(delta) = last_combined_event.scroll_location {
1228+
last_combined_event.scroll_location = ScrollLocation::Delta(delta + this_delta);
1229+
last_combined_event.event_count += 1
1230+
}
12021231
}
12031232
}
12041233
}
12051234

12061235
// TODO(gw): Support zoom (WR issue #28).
12071236
if let Some(combined_event) = last_combined_event {
1208-
let delta = (combined_event.delta / self.scale).to_untyped();
1209-
let delta = webrender_traits::LayoutPoint::from_untyped(&delta);
1237+
let scroll_location = match combined_event.scroll_location {
1238+
ScrollLocation::Delta(delta) => {
1239+
let scaled_delta = (TypedPoint2D::from_untyped(&delta.to_untyped()) / self.scale)
1240+
.to_untyped();
1241+
let calculated_delta = webrender_traits::LayoutPoint::from_untyped(&scaled_delta);
1242+
ScrollLocation::Delta(calculated_delta)
1243+
},
1244+
// Leave ScrollLocation unchanged if it is Start or End location.
1245+
sl @ ScrollLocation::Start | sl @ ScrollLocation::End => sl,
1246+
};
12101247
let cursor = (combined_event.cursor.to_f32() / self.scale).to_untyped();
1211-
let location = webrender_traits::ScrollLocation::Delta(delta);
12121248
let cursor = webrender_traits::WorldPoint::from_untyped(&cursor);
1213-
self.webrender_api.scroll(location, cursor, combined_event.phase);
1249+
self.webrender_api.scroll(scroll_location, cursor, combined_event.phase);
12141250
self.waiting_for_results_of_scroll = true
12151251
}
12161252

@@ -1305,7 +1341,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
13051341
fn on_pinch_zoom_window_event(&mut self, magnification: f32) {
13061342
self.pending_scroll_zoom_events.push(ScrollZoomEvent {
13071343
magnification: magnification,
1308-
delta: TypedPoint2D::zero(), // TODO: Scroll to keep the center in view?
1344+
scroll_location: ScrollLocation::Delta(TypedPoint2D::zero()), // TODO: Scroll to keep the center in view?
13091345
cursor: TypedPoint2D::new(-1, -1), // Make sure this hits the base layer.
13101346
phase: ScrollEventPhase::Move(true),
13111347
event_count: 1,
@@ -1703,6 +1739,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
17031739
}
17041740
}
17051741

1742+
17061743
/// Why we performed a composite. This is used for debugging.
17071744
#[derive(Copy, Clone, PartialEq, Debug)]
17081745
pub enum CompositingReason {

components/compositing/windowing.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use servo_geometry::ScreenPx;
1616
use servo_url::ServoUrl;
1717
use std::fmt::{Debug, Error, Formatter};
1818
use style_traits::cursor::Cursor;
19+
use webrender_traits::ScrollLocation;
1920

2021
#[derive(Clone)]
2122
pub enum MouseWindowEvent {
@@ -62,7 +63,7 @@ pub enum WindowEvent {
6263
Touch(TouchEventType, TouchId, TypedPoint2D<f32, DevicePixel>),
6364
/// Sent when the user scrolls. The first point is the delta and the second point is the
6465
/// origin.
65-
Scroll(TypedPoint2D<f32, DevicePixel>, TypedPoint2D<i32, DevicePixel>, TouchEventType),
66+
Scroll(ScrollLocation, TypedPoint2D<i32, DevicePixel>, TouchEventType),
6667
/// Sent when the user zooms.
6768
Zoom(f32),
6869
/// Simulated "pinch zoom" gesture for non-touch platforms (e.g. ctrl-scrollwheel).

ports/glutin/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ servo_config = {path = "../../components/config"}
2323
servo_url = {path = "../../components/url"}
2424
style_traits = {path = "../../components/style_traits"}
2525

26+
[dependencies.webrender_traits]
27+
git = "https://github.com/servo/webrender"
28+
default_features = false
29+
2630
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
2731
osmesa-sys = "0.1.2"
2832

ports/glutin/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ extern crate servo_config;
2222
extern crate servo_geometry;
2323
extern crate servo_url;
2424
extern crate style_traits;
25+
extern crate webrender_traits;
26+
2527
#[cfg(target_os = "windows")] extern crate winapi;
2628
#[cfg(target_os = "windows")] extern crate user32;
2729
#[cfg(target_os = "windows")] extern crate gdi32;

ports/glutin/window.rs

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use std::sync::mpsc::{Sender, channel};
4242
use style_traits::cursor::Cursor;
4343
#[cfg(target_os = "windows")]
4444
use user32;
45+
use webrender_traits::ScrollLocation;
4546
#[cfg(target_os = "windows")]
4647
use winapi;
4748

@@ -425,8 +426,9 @@ impl Window {
425426
MouseScrollDelta::LineDelta(dx, dy) => (dx, dy * LINE_HEIGHT),
426427
MouseScrollDelta::PixelDelta(dx, dy) => (dx, dy),
427428
};
429+
let scroll_location = ScrollLocation::Delta(TypedPoint2D::new(dx, dy));
428430
let phase = glutin_phase_to_touch_event_type(phase);
429-
self.scroll_window(dx, dy, phase);
431+
self.scroll_window(scroll_location, phase);
430432
},
431433
Event::Touch(touch) => {
432434
use script_traits::TouchId;
@@ -461,16 +463,19 @@ impl Window {
461463
}
462464

463465
/// Helper function to send a scroll event.
464-
fn scroll_window(&self, mut dx: f32, mut dy: f32, phase: TouchEventType) {
466+
fn scroll_window(&self, scroll_location: ScrollLocation, phase: TouchEventType) {
465467
// Scroll events snap to the major axis of movement, with vertical
466468
// preferred over horizontal.
467-
if dy.abs() >= dx.abs() {
468-
dx = 0.0;
469-
} else {
470-
dy = 0.0;
469+
if let ScrollLocation::Delta(mut delta) = scroll_location {
470+
if delta.y.abs() >= delta.x.abs() {
471+
delta.x = 0.0;
472+
} else {
473+
delta.y = 0.0;
474+
}
471475
}
476+
472477
let mouse_pos = self.mouse_pos.get();
473-
let event = WindowEvent::Scroll(TypedPoint2D::new(dx as f32, dy as f32),
478+
let event = WindowEvent::Scroll(scroll_location,
474479
TypedPoint2D::new(mouse_pos.x as i32, mouse_pos.y as i32),
475480
phase);
476481
self.event_queue.borrow_mut().push(event);
@@ -1034,33 +1039,46 @@ impl WindowMethods for Window {
10341039

10351040
(NONE, None, Key::PageDown) |
10361041
(NONE, Some(' '), _) => {
1037-
self.scroll_window(0.0,
1042+
let scroll_location = ScrollLocation::Delta(TypedPoint2D::new(0.0,
10381043
-self.framebuffer_size()
10391044
.to_f32()
10401045
.to_untyped()
1041-
.height + 2.0 * LINE_HEIGHT,
1046+
.height + 2.0 * LINE_HEIGHT));
1047+
self.scroll_window(scroll_location,
10421048
TouchEventType::Move);
10431049
}
10441050
(NONE, None, Key::PageUp) |
10451051
(SHIFT, Some(' '), _) => {
1046-
self.scroll_window(0.0,
1052+
let scroll_location = ScrollLocation::Delta(TypedPoint2D::new(0.0,
10471053
self.framebuffer_size()
10481054
.to_f32()
10491055
.to_untyped()
1050-
.height - 2.0 * LINE_HEIGHT,
1056+
.height - 2.0 * LINE_HEIGHT));
1057+
self.scroll_window(scroll_location,
10511058
TouchEventType::Move);
10521059
}
1060+
1061+
(NONE, None, Key::Home) => {
1062+
self.scroll_window(ScrollLocation::Start, TouchEventType::Move);
1063+
}
1064+
1065+
(NONE, None, Key::End) => {
1066+
self.scroll_window(ScrollLocation::End, TouchEventType::Move);
1067+
}
1068+
10531069
(NONE, None, Key::Up) => {
1054-
self.scroll_window(0.0, 3.0 * LINE_HEIGHT, TouchEventType::Move);
1070+
self.scroll_window(ScrollLocation::Delta(TypedPoint2D::new(0.0, 3.0 * LINE_HEIGHT)),
1071+
TouchEventType::Move);
10551072
}
10561073
(NONE, None, Key::Down) => {
1057-
self.scroll_window(0.0, -3.0 * LINE_HEIGHT, TouchEventType::Move);
1074+
self.scroll_window(ScrollLocation::Delta(TypedPoint2D::new(0.0, -3.0 * LINE_HEIGHT)),
1075+
TouchEventType::Move);
10581076
}
10591077
(NONE, None, Key::Left) => {
1060-
self.scroll_window(LINE_HEIGHT, 0.0, TouchEventType::Move);
1078+
self.scroll_window(ScrollLocation::Delta(TypedPoint2D::new(LINE_HEIGHT, 0.0)), TouchEventType::Move);
10611079
}
10621080
(NONE, None, Key::Right) => {
1063-
self.scroll_window(-LINE_HEIGHT, 0.0, TouchEventType::Move);
1081+
self.scroll_window(ScrollLocation::Delta(TypedPoint2D::new(-LINE_HEIGHT, 0.0)), TouchEventType::Move);
10641082
}
10651083
(CMD_OR_CONTROL, Some('r'), _) => {
10661084
if let Some(true) = PREFS.get("shell.builtin-key-shortcuts.enabled").as_boolean() {

0 commit comments

Comments
 (0)