mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Implement scroll event listener
Signed-off-by: PotatoCP <kenzieradityatirtarahardja.18@gmail.com> Co-authored-by: Asun0204 <asun0204@163.com>
This commit is contained in:
parent
7f0cebd442
commit
2d3fa482d7
5 changed files with 88 additions and 20 deletions
|
@ -12,8 +12,8 @@ use compositing_traits::{SendableFrameTree, WebViewTrait};
|
|||
use constellation_traits::{EmbedderToConstellationMessage, ScrollState, WindowSizeType};
|
||||
use embedder_traits::{
|
||||
AnimationState, CompositorHitTestResult, InputEvent, MouseButton, MouseButtonAction,
|
||||
MouseButtonEvent, MouseMoveEvent, ShutdownState, TouchEvent, TouchEventResult, TouchEventType,
|
||||
TouchId, ViewportDetails,
|
||||
MouseButtonEvent, MouseMoveEvent, ScrollEvent as EmbedderScrollEvent, ShutdownState,
|
||||
TouchEvent, TouchEventResult, TouchEventType, TouchId, ViewportDetails,
|
||||
};
|
||||
use euclid::{Box2D, Point2D, Scale, Size2D, Vector2D};
|
||||
use fnv::FnvHashSet;
|
||||
|
@ -51,9 +51,9 @@ enum ScrollZoomEvent {
|
|||
Scroll(ScrollEvent),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct ScrollResult {
|
||||
pub pipeline_id: PipelineId,
|
||||
pub hit_test_result: CompositorHitTestResult,
|
||||
pub external_scroll_id: ExternalScrollId,
|
||||
pub offset: LayoutVector2D,
|
||||
}
|
||||
|
@ -813,8 +813,14 @@ impl WebViewRenderer {
|
|||
combined_event.scroll_location,
|
||||
)
|
||||
});
|
||||
if let Some(scroll_result) = scroll_result {
|
||||
self.send_scroll_positions_to_layout_for_pipeline(scroll_result.pipeline_id);
|
||||
if let Some(scroll_result) = scroll_result.clone() {
|
||||
self.send_scroll_positions_to_layout_for_pipeline(
|
||||
scroll_result.hit_test_result.pipeline_id,
|
||||
);
|
||||
self.dispatch_scroll_event(
|
||||
scroll_result.external_scroll_id,
|
||||
scroll_result.hit_test_result,
|
||||
);
|
||||
}
|
||||
|
||||
let pinch_zoom_result = match self
|
||||
|
@ -829,8 +835,8 @@ impl WebViewRenderer {
|
|||
|
||||
/// Perform a hit test at the given [`DevicePoint`] and apply the [`ScrollLocation`]
|
||||
/// scrolling to the applicable scroll node under that point. If a scroll was
|
||||
/// performed, returns the [`PipelineId`] of the node scrolled, the id, and the final
|
||||
/// scroll delta.
|
||||
/// performed, returns the hit test result contains [`PipelineId`] of the node
|
||||
/// scrolled, the id, and the final scroll delta.
|
||||
fn scroll_node_at_device_point(
|
||||
&mut self,
|
||||
cursor: DevicePoint,
|
||||
|
@ -864,20 +870,17 @@ impl WebViewRenderer {
|
|||
// This is needed to propagate the scroll events from a pipeline representing an iframe to
|
||||
// its ancestor pipelines.
|
||||
let mut previous_pipeline_id = None;
|
||||
for CompositorHitTestResult {
|
||||
pipeline_id,
|
||||
scroll_tree_node,
|
||||
..
|
||||
} in hit_test_results.iter()
|
||||
for hit_test_result in hit_test_results.iter() {
|
||||
let pipeline_details = self.pipelines.get_mut(&hit_test_result.pipeline_id)?;
|
||||
if previous_pipeline_id.replace(&hit_test_result.pipeline_id) !=
|
||||
Some(&hit_test_result.pipeline_id)
|
||||
{
|
||||
let pipeline_details = self.pipelines.get_mut(pipeline_id)?;
|
||||
if previous_pipeline_id.replace(pipeline_id) != Some(pipeline_id) {
|
||||
let scroll_result = pipeline_details
|
||||
.scroll_tree
|
||||
.scroll_node_or_ancestor(scroll_tree_node, scroll_location);
|
||||
.scroll_node_or_ancestor(&hit_test_result.scroll_tree_node, scroll_location);
|
||||
if let Some((external_scroll_id, offset)) = scroll_result {
|
||||
return Some(ScrollResult {
|
||||
pipeline_id: *pipeline_id,
|
||||
hit_test_result: hit_test_result.clone(),
|
||||
external_scroll_id,
|
||||
offset,
|
||||
});
|
||||
|
@ -887,6 +890,22 @@ impl WebViewRenderer {
|
|||
None
|
||||
}
|
||||
|
||||
fn dispatch_scroll_event(
|
||||
&self,
|
||||
external_id: ExternalScrollId,
|
||||
hit_test_result: CompositorHitTestResult,
|
||||
) {
|
||||
let event = InputEvent::Scroll(EmbedderScrollEvent { external_id });
|
||||
let msg = EmbedderToConstellationMessage::ForwardInputEvent(
|
||||
self.id,
|
||||
event,
|
||||
Some(hit_test_result),
|
||||
);
|
||||
if let Err(e) = self.global.borrow().constellation_sender.send(msg) {
|
||||
warn!("Sending scroll event to constellation failed ({:?}).", e);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn pinch_zoom_level(&self) -> Scale<f32, DevicePixel, DevicePixel> {
|
||||
Scale::new(self.viewport_zoom.get())
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@ mod from_compositor {
|
|||
InputEvent::MouseMove(..) => target_variant!("MouseMove"),
|
||||
InputEvent::Touch(..) => target_variant!("Touch"),
|
||||
InputEvent::Wheel(..) => target_variant!("Wheel"),
|
||||
InputEvent::Scroll(..) => target_variant!("Scroll"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,8 @@ use dom_struct::dom_struct;
|
|||
use embedder_traits::{
|
||||
AllowOrDeny, AnimationState, CompositorHitTestResult, ContextMenuResult, EditingActionEvent,
|
||||
EmbedderMsg, FocusSequenceNumber, ImeEvent, InputEvent, LoadStatus, MouseButton,
|
||||
MouseButtonAction, MouseButtonEvent, TouchEvent, TouchEventType, TouchId, WheelEvent,
|
||||
MouseButtonAction, MouseButtonEvent, ScrollEvent, TouchEvent, TouchEventType, TouchId,
|
||||
UntrustedNodeAddress, WheelEvent,
|
||||
};
|
||||
use encoding_rs::{Encoding, UTF_8};
|
||||
use euclid::default::{Point2D, Rect, Size2D};
|
||||
|
@ -54,7 +55,7 @@ use profile_traits::ipc as profile_ipc;
|
|||
use profile_traits::time::TimerMetadataFrameType;
|
||||
use regex::bytes::Regex;
|
||||
use script_bindings::interfaces::DocumentHelpers;
|
||||
use script_layout_interface::{PendingRestyle, TrustedNodeAddress};
|
||||
use script_layout_interface::{PendingRestyle, TrustedNodeAddress, node_id_from_scroll_id};
|
||||
use script_traits::{ConstellationInputEvent, DocumentActivity, ProgressiveWebMetricType};
|
||||
use servo_arc::Arc;
|
||||
use servo_config::pref;
|
||||
|
@ -2337,6 +2338,40 @@ impl Document {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) fn handle_scroll_event(&self, event: ScrollEvent, can_gc: CanGc) {
|
||||
// <https://drafts.csswg.org/cssom-view/#scrolling-events>
|
||||
// If target is a Document, fire an event named scroll that bubbles at target.
|
||||
if event.external_id.is_root() {
|
||||
let Some(document) = self
|
||||
.node
|
||||
.inclusive_ancestors(ShadowIncluding::No)
|
||||
.filter_map(DomRoot::downcast::<Document>)
|
||||
.next()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
DomRoot::upcast::<EventTarget>(document)
|
||||
.fire_bubbling_event(Atom::from("scroll"), can_gc);
|
||||
} else {
|
||||
// Otherwise, fire an event named scroll at target.
|
||||
let Some(node_id) = node_id_from_scroll_id(event.external_id.0 as usize) else {
|
||||
return;
|
||||
};
|
||||
let node = unsafe {
|
||||
node::from_untrusted_node_address(UntrustedNodeAddress::from_id(node_id))
|
||||
};
|
||||
let Some(element) = node
|
||||
.inclusive_ancestors(ShadowIncluding::No)
|
||||
.filter_map(DomRoot::downcast::<Element>)
|
||||
.next()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
DomRoot::upcast::<EventTarget>(element).fire_event(Atom::from("scroll"), can_gc);
|
||||
}
|
||||
}
|
||||
|
||||
/// The entry point for all key processing for web content
|
||||
pub(crate) fn dispatch_key_event(
|
||||
&self,
|
||||
|
|
|
@ -1143,6 +1143,9 @@ impl ScriptThread {
|
|||
InputEvent::EditingAction(editing_action_event) => {
|
||||
document.handle_editing_action(editing_action_event, can_gc);
|
||||
},
|
||||
InputEvent::Scroll(scroll_event) => {
|
||||
document.handle_scroll_event(scroll_event, can_gc);
|
||||
},
|
||||
}
|
||||
}
|
||||
ScriptThread::set_user_interacting(false);
|
||||
|
|
|
@ -6,6 +6,7 @@ use keyboard_types::{CompositionEvent, KeyboardEvent};
|
|||
use log::error;
|
||||
use malloc_size_of_derive::MallocSizeOf;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use webrender_api::ExternalScrollId;
|
||||
use webrender_api::units::DevicePoint;
|
||||
|
||||
use crate::WebDriverMessageId;
|
||||
|
@ -21,6 +22,7 @@ pub enum InputEvent {
|
|||
MouseMove(MouseMoveEvent),
|
||||
Touch(TouchEvent),
|
||||
Wheel(WheelEvent),
|
||||
Scroll(ScrollEvent),
|
||||
}
|
||||
|
||||
/// An editing action that should be performed on a `WebView`.
|
||||
|
@ -42,6 +44,7 @@ impl InputEvent {
|
|||
InputEvent::MouseMove(event) => Some(event.point),
|
||||
InputEvent::Touch(event) => Some(event.point),
|
||||
InputEvent::Wheel(event) => Some(event.point),
|
||||
InputEvent::Scroll(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,6 +58,7 @@ impl InputEvent {
|
|||
InputEvent::MouseMove(event) => event.webdriver_id,
|
||||
InputEvent::Touch(..) => None,
|
||||
InputEvent::Wheel(..) => None,
|
||||
InputEvent::Scroll(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,6 +76,7 @@ impl InputEvent {
|
|||
},
|
||||
InputEvent::Touch(..) => {},
|
||||
InputEvent::Wheel(..) => {},
|
||||
InputEvent::Scroll(..) => {},
|
||||
};
|
||||
|
||||
self
|
||||
|
@ -277,6 +282,11 @@ pub struct WheelEvent {
|
|||
pub point: DevicePoint,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||
pub struct ScrollEvent {
|
||||
pub external_id: ExternalScrollId,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub enum ImeEvent {
|
||||
Composition(CompositionEvent),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue