From b5482e34c017c64fae6f5c1db41880d826546a46 Mon Sep 17 00:00:00 2001 From: Mukilan Thiyagarajan Date: Mon, 22 Jul 2024 18:12:44 +0530 Subject: [PATCH] compositor: propagate scroll events across pipelines (#32829) Currently we don't propagate the scroll events across pipeline and scroll only nodes contained within the nearest pipeline that passes hit test at a gived point. This causes iframes to "capture" the scroll and halt the scrolling process once the iframe has been scrolled all the way. The expected behaviour is that the parent page begins to scroll once the iframe has been scrolled fully. The issue is present in both desktop and mobile, but was more noticeable on mobile, especially on the default servo.org page, because of the relative sizes of the YouTube video's iframe wrt to the parent. Signed-off-by: Mukilan Thiyagarajan Co-authored-by: Martin Robinson --- components/compositing/compositor.rs | 36 ++++++++++++++++++---------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 2012f7fe31c..ec5a8513304 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -1808,19 +1808,31 @@ impl IOCompositor { ScrollLocation::Start | ScrollLocation::End => scroll_location, }; - let hit_test_result = match self.hit_test_at_point(cursor) { - Some(result) => result, - None => return None, - }; + let hit_test_results = + self.hit_test_at_point_with_flags_and_pipeline(cursor, HitTestFlags::FIND_ALL, None); - let pipeline_details = match self.pipeline_details.get_mut(&hit_test_result.pipeline_id) { - Some(details) => details, - None => return None, - }; - pipeline_details - .scroll_tree - .scroll_node_or_ancestor(&hit_test_result.scroll_tree_node, scroll_location) - .map(|(external_id, offset)| (hit_test_result.pipeline_id, external_id, offset)) + // Iterate through all hit test results, processing only the first node of each pipeline. + // 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() + { + if previous_pipeline_id.replace(pipeline_id) != Some(pipeline_id) { + let scroll_result = self + .pipeline_details + .get_mut(&pipeline_id)? + .scroll_tree + .scroll_node_or_ancestor(&scroll_tree_node, scroll_location); + if let Some((external_id, offset)) = scroll_result { + return Some((*pipeline_id, external_id, offset)); + } + } + } + None } /// If there are any animations running, dispatches appropriate messages to the constellation.