diff --git a/components/layout_2020/display_list/mod.rs b/components/layout_2020/display_list/mod.rs index a18df1687b4..703e8c523ba 100644 --- a/components/layout_2020/display_list/mod.rs +++ b/components/layout_2020/display_list/mod.rs @@ -33,7 +33,7 @@ use style::values::specified::text::TextDecorationLine; use style::values::specified::ui::CursorKind; use style::Zero; use style_traits::{CSSPixel, DevicePixel}; -use webrender_api::units::{LayoutPixel, LayoutSize}; +use webrender_api::units::{LayoutPixel, LayoutRect, LayoutSize}; use webrender_api::{ self as wr, units, BorderDetails, BoxShadowClipMode, ClipChainId, CommonItemProperties, ImageRendering, NinePatchBorder, NinePatchBorderSource, @@ -250,14 +250,20 @@ impl Fragment { builder: &mut DisplayListBuilder, containing_block: &PhysicalRect, section: StackingContextSection, + is_hit_test_for_scrollable_overflow: bool, ) { match self { - Fragment::Box(b) | Fragment::Float(b) => match b.style.get_inherited_box().visibility { - Visibility::Visible => { - BuilderForBoxFragment::new(b, containing_block).build(builder, section) - }, - Visibility::Hidden => (), - Visibility::Collapse => (), + Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => { + match box_fragment.style.get_inherited_box().visibility { + Visibility::Visible => BuilderForBoxFragment::new( + box_fragment, + containing_block, + is_hit_test_for_scrollable_overflow, + ) + .build(builder, section), + Visibility::Hidden => (), + Visibility::Collapse => (), + } }, Fragment::AbsoluteOrFixedPositioned(_) => {}, Fragment::Positioning(positioning_fragment) => { @@ -508,10 +514,15 @@ struct BuilderForBoxFragment<'a> { border_edge_clip_chain_id: RefCell>, padding_edge_clip_chain_id: RefCell>, content_edge_clip_chain_id: RefCell>, + is_hit_test_for_scrollable_overflow: bool, } impl<'a> BuilderForBoxFragment<'a> { - fn new(fragment: &'a BoxFragment, containing_block: &'a PhysicalRect) -> Self { + fn new( + fragment: &'a BoxFragment, + containing_block: &'a PhysicalRect, + is_hit_test_for_scrollable_overflow: bool, + ) -> Self { let border_rect = fragment .border_rect() .translate(containing_block.origin.to_vector()); @@ -550,6 +561,7 @@ impl<'a> BuilderForBoxFragment<'a> { border_edge_clip_chain_id: RefCell::new(None), padding_edge_clip_chain_id: RefCell::new(None), content_edge_clip_chain_id: RefCell::new(None), + is_hit_test_for_scrollable_overflow, } } @@ -635,25 +647,31 @@ impl<'a> BuilderForBoxFragment<'a> { } fn build(&mut self, builder: &mut DisplayListBuilder, section: StackingContextSection) { + if self.is_hit_test_for_scrollable_overflow { + self.build_hit_test(builder, self.fragment.scrollable_overflow().to_webrender()); + return; + } + if section == StackingContextSection::Outline { self.build_outline(builder); - } else { - self.build_hit_test(builder); - if self - .fragment - .base - .flags - .contains(FragmentFlags::DO_NOT_PAINT) - { - return; - } - self.build_background(builder); - self.build_box_shadow(builder); - self.build_border(builder); + return; } + + self.build_hit_test(builder, self.border_rect); + if self + .fragment + .base + .flags + .contains(FragmentFlags::DO_NOT_PAINT) + { + return; + } + self.build_background(builder); + self.build_box_shadow(builder); + self.build_border(builder); } - fn build_hit_test(&self, builder: &mut DisplayListBuilder) { + fn build_hit_test(&self, builder: &mut DisplayListBuilder, rect: LayoutRect) { let hit_info = builder.hit_info( &self.fragment.style, self.fragment.base.tag, @@ -664,7 +682,7 @@ impl<'a> BuilderForBoxFragment<'a> { None => return, }; - let mut common = builder.common_properties(self.border_rect, &self.fragment.style); + let mut common = builder.common_properties(rect, &self.fragment.style); if let Some(clip_chain_id) = self.border_edge_clip(builder, false) { common.clip_chain_id = clip_chain_id; } diff --git a/components/layout_2020/display_list/stacking_context.rs b/components/layout_2020/display_list/stacking_context.rs index e76ab0f9716..76235bca453 100644 --- a/components/layout_2020/display_list/stacking_context.rs +++ b/components/layout_2020/display_list/stacking_context.rs @@ -261,6 +261,7 @@ pub(crate) enum StackingContextContent { section: StackingContextSection, containing_block: PhysicalRect, fragment: ArcRefCell, + is_hit_test_for_scrollable_overflow: bool, }, /// An index into [StackingContext::atomic_inline_stacking_containers]. @@ -290,13 +291,17 @@ impl StackingContextContent { section, containing_block, fragment, + is_hit_test_for_scrollable_overflow, } => { builder.current_scroll_node_id = *scroll_node_id; builder.current_reference_frame_scroll_node_id = *reference_frame_scroll_node_id; builder.current_clip_chain_id = *clip_chain_id; - fragment - .borrow() - .build_display_list(builder, containing_block, *section); + fragment.borrow().build_display_list( + builder, + containing_block, + *section, + *is_hit_test_for_scrollable_overflow, + ); }, Self::AtomicInlineStackingContainer { index } => { inline_stacking_containers[*index].build_display_list(builder); @@ -666,7 +671,8 @@ impl StackingContext { } } - let mut fragment_builder = BuilderForBoxFragment::new(box_fragment, containing_block); + let mut fragment_builder = + BuilderForBoxFragment::new(box_fragment, containing_block, false); let painter = super::background::BackgroundPainter { style, painting_area_override: Some(painting_area), @@ -804,10 +810,10 @@ impl StackingContext { match field { DebugPrintField::Contents => match self.contents[*index] { StackingContextContent::Fragment { section, .. } => { - tree.add_item(format!("{:?}", section)); + tree.add_item(format!("{section:?}")); }, StackingContextContent::AtomicInlineStackingContainer { index } => { - tree.new_level(format!("AtomicInlineStackingContainer #{}", index)); + tree.new_level(format!("AtomicInlineStackingContainer #{index}")); self.atomic_inline_stacking_containers[index].debug_print_with_tree(tree); tree.end_level(); }, @@ -912,6 +918,7 @@ impl Fragment { clip_chain_id: containing_block.clip_chain_id, containing_block: containing_block.rect, fragment: fragment_ref.clone(), + is_hit_test_for_scrollable_overflow: false, }); }, } @@ -923,6 +930,11 @@ struct ReferenceFrameData { transform: LayoutTransform, kind: wr::ReferenceFrameKind, } +struct ScrollFrameData { + scroll_tree_node_id: ScrollTreeNodeId, + clip_chain_id: wr::ClipChainId, + scroll_frame_rect: LayoutRect, +} impl BoxFragment { fn get_stacking_context_type(&self) -> Option { @@ -1080,7 +1092,7 @@ impl BoxFragment { display_list, &containing_block.scroll_node_id, &containing_block.clip_chain_id, - BuilderForBoxFragment::new(self, &containing_block.rect), + BuilderForBoxFragment::new(self, &containing_block.rect, false), ) .unwrap_or(containing_block.clip_chain_id); @@ -1152,7 +1164,7 @@ impl BoxFragment { display_list, &new_scroll_node_id, &new_clip_chain_id, - BuilderForBoxFragment::new(self, &containing_block.rect), + BuilderForBoxFragment::new(self, &containing_block.rect, false), ) { new_clip_chain_id = clip_chain_id; } @@ -1181,6 +1193,7 @@ impl BoxFragment { section: self.get_stacking_context_section(), containing_block: containing_block.rect, fragment: fragment.clone(), + is_hit_test_for_scrollable_overflow: false, }); if !self.style.get_outline().outline_width.is_zero() { @@ -1193,22 +1206,33 @@ impl BoxFragment { section: StackingContextSection::Outline, containing_block: containing_block.rect, fragment: fragment.clone(), + is_hit_test_for_scrollable_overflow: false, }); } // We want to build the scroll frame after the background and border, because // they shouldn't scroll with the rest of the box content. - if let Some((scroll_node_id, clip_chain_id, scroll_frame_size)) = self - .build_scroll_frame_if_necessary( - display_list, - &new_scroll_node_id, - &new_clip_chain_id, - &containing_block.rect, - ) - { - new_scroll_node_id = scroll_node_id; - new_clip_chain_id = clip_chain_id; - new_scroll_frame_size = Some(scroll_frame_size); + if let Some(scroll_frame_data) = self.build_scroll_frame_if_necessary( + display_list, + &new_scroll_node_id, + &new_clip_chain_id, + &containing_block.rect, + ) { + new_scroll_node_id = scroll_frame_data.scroll_tree_node_id; + new_clip_chain_id = scroll_frame_data.clip_chain_id; + new_scroll_frame_size = Some(scroll_frame_data.scroll_frame_rect.size()); + + stacking_context + .contents + .push(StackingContextContent::Fragment { + scroll_node_id: new_scroll_node_id, + reference_frame_scroll_node_id: reference_frame_scroll_node_id_for_fragments, + clip_chain_id: new_clip_chain_id, + section: self.get_stacking_context_section(), + containing_block: containing_block.rect, + fragment: fragment.clone(), + is_hit_test_for_scrollable_overflow: true, + }); } let padding_rect = self @@ -1297,8 +1321,7 @@ impl BoxFragment { parent_scroll_node_id: &ScrollTreeNodeId, parent_clip_id: &wr::ClipChainId, containing_block_rect: &PhysicalRect, - ) -> Option<(ScrollTreeNodeId, wr::ClipChainId, LayoutSize)> { - let overflow = self.style.effective_overflow(); + ) -> Option { if !self.style.establishes_scroll_container() { return None; } @@ -1327,6 +1350,7 @@ impl BoxFragment { display_list.wr.pipeline_id, ); + let overflow = self.style.effective_overflow(); let sensitivity = if ComputedOverflow::Hidden == overflow.x && ComputedOverflow::Hidden == overflow.y { ScrollSensitivity::Script @@ -1334,21 +1358,26 @@ impl BoxFragment { ScrollSensitivity::ScriptAndInputEvents }; - let padding_rect = self + let scroll_frame_rect = self .padding_rect() .translate(containing_block_rect.origin.to_vector()) .to_webrender(); + let content_rect = self.scrollable_overflow().to_webrender(); let (scroll_tree_node_id, clip_chain_id) = display_list.define_scroll_frame( parent_scroll_node_id, parent_clip_id, external_id, - self.scrollable_overflow().to_webrender(), - padding_rect, + content_rect, + scroll_frame_rect, sensitivity, ); - Some((scroll_tree_node_id, clip_chain_id, padding_rect.size())) + Some(ScrollFrameData { + scroll_tree_node_id, + clip_chain_id, + scroll_frame_rect, + }) } fn build_sticky_frame_if_necessary( diff --git a/components/shared/webrender/display_list.rs b/components/shared/webrender/display_list.rs index 635c4fba0f0..78e8e9492f6 100644 --- a/components/shared/webrender/display_list.rs +++ b/components/shared/webrender/display_list.rs @@ -21,7 +21,7 @@ pub enum ScrollSensitivity { /// Information that Servo keeps alongside WebRender display items /// in order to add more context to hit test results. -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, PartialEq, Serialize)] pub struct HitTestInfo { /// The id of the node of this hit test item. pub node: u64, @@ -327,17 +327,19 @@ impl CompositorDisplayListInfo { cursor: Option, scroll_tree_node: ScrollTreeNodeId, ) -> usize { + let hit_test_info = HitTestInfo { + node, + cursor, + scroll_tree_node, + }; + if let Some(last) = self.hit_test_info.last() { - if node == last.node && cursor == last.cursor { + if hit_test_info == *last { return self.hit_test_info.len() - 1; } } - self.hit_test_info.push(HitTestInfo { - node, - cursor, - scroll_tree_node, - }); + self.hit_test_info.push(hit_test_info); self.hit_test_info.len() - 1 } }