diff options
Diffstat (limited to 'components/shared/compositing')
-rw-r--r-- | components/shared/compositing/display_list.rs | 154 | ||||
-rw-r--r-- | components/shared/compositing/lib.rs | 2 | ||||
-rw-r--r-- | components/shared/compositing/tests/compositor.rs | 43 |
3 files changed, 140 insertions, 59 deletions
diff --git a/components/shared/compositing/display_list.rs b/components/shared/compositing/display_list.rs index 6aa822cb145..4fb0d5e94db 100644 --- a/components/shared/compositing/display_list.rs +++ b/components/shared/compositing/display_list.rs @@ -6,11 +6,17 @@ use base::id::ScrollTreeNodeId; use embedder_traits::Cursor; +use euclid::SideOffsets2D; use malloc_size_of_derive::MallocSizeOf; use serde::{Deserialize, Serialize}; use style::values::specified::Overflow; -use webrender_api::units::{LayoutSize, LayoutVector2D}; -use webrender_api::{Epoch, ExternalScrollId, PipelineId, ScrollLocation, SpatialId}; +use webrender_api::units::{ + LayoutPixel, LayoutPoint, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D, +}; +use webrender_api::{ + Epoch, ExternalScrollId, PipelineId, ReferenceFrameKind, ScrollLocation, SpatialId, + StickyOffsetBounds, TransformStyle, +}; /// The scroll sensitivity of a scroll node in a particular axis ie whether it can be scrolled due to /// input events and script events or only script events. @@ -56,6 +62,29 @@ pub struct HitTestInfo { pub scroll_tree_node: ScrollTreeNodeId, } +#[derive(Debug, Deserialize, Serialize)] +pub enum SpatialTreeNodeInfo { + ReferenceFrame(ReferenceFrameNodeInfo), + Scroll(ScrollableNodeInfo), + Sticky(StickyNodeInfo), +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct StickyNodeInfo { + pub frame_rect: LayoutRect, + pub margins: SideOffsets2D<Option<f32>, LayoutPixel>, + pub vertical_offset_bounds: StickyOffsetBounds, + pub horizontal_offset_bounds: StickyOffsetBounds, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct ReferenceFrameNodeInfo { + pub origin: LayoutPoint, + pub transform_style: TransformStyle, + pub transform: LayoutTransform, + pub kind: ReferenceFrameKind, +} + /// Data stored for nodes in the [ScrollTree] that actually scroll, /// as opposed to reference frames and sticky nodes which do not. #[derive(Debug, Deserialize, Serialize)] @@ -64,8 +93,11 @@ pub struct ScrollableNodeInfo { /// it between successive re-layouts. pub external_id: ExternalScrollId, - /// Amount that this `ScrollableNode` can scroll in both directions. - pub scrollable_size: LayoutSize, + /// The content rectangle for this scroll node; + pub content_rect: LayoutRect, + + /// The clip rectange for this scroll node. + pub clip_rect: LayoutRect, /// Whether this `ScrollableNode` is sensitive to input events. pub scroll_sensitivity: AxesScrollSensitivity, @@ -74,6 +106,12 @@ pub struct ScrollableNodeInfo { pub offset: LayoutVector2D, } +impl ScrollableNodeInfo { + fn scrollable_size(&self) -> LayoutSize { + self.content_rect.size() - self.clip_rect.size() + } +} + #[derive(Debug, Deserialize, Serialize)] /// A node in a tree of scroll nodes. This may either be a scrollable /// node which responds to scroll events or a non-scrollable one. @@ -82,35 +120,51 @@ pub struct ScrollTreeNode { /// None then this is the root node. pub parent: Option<ScrollTreeNodeId>, - /// Scrolling data which will not be None if this is a scrolling node. - pub scroll_info: Option<ScrollableNodeInfo>, + /// The WebRender id, which is filled in when this tree is serialiezd + /// into a WebRender display list. + pub webrender_id: Option<SpatialId>, + + /// Specific information about this node, depending on whether it is a scroll node + /// or a reference frame. + pub info: SpatialTreeNodeInfo, } impl ScrollTreeNode { + /// Get the WebRender [`SpatialId`] for the given [`ScrollNodeId`]. This will + /// panic if [`ScrollTree::build_display_list`] has not been called yet. + pub fn webrender_id(&self) -> SpatialId { + self.webrender_id + .expect("Should have called ScrollTree::build_display_list before querying SpatialId") + } + /// Get the external id of this node. pub fn external_id(&self) -> Option<ExternalScrollId> { - self.scroll_info.as_ref().map(|info| info.external_id) + match self.info { + SpatialTreeNodeInfo::Scroll(ref info) => Some(info.external_id), + _ => None, + } } /// Get the offset id of this node if it applies. pub fn offset(&self) -> Option<LayoutVector2D> { - self.scroll_info.as_ref().map(|info| info.offset) + match self.info { + SpatialTreeNodeInfo::Scroll(ref info) => Some(info.offset), + _ => None, + } } /// Set the offset for this node, returns false if this was a /// non-scrolling node for which you cannot set the offset. pub fn set_offset(&mut self, new_offset: LayoutVector2D) -> bool { - match self.scroll_info { - Some(ref mut info) => { - let scrollable_width = info.scrollable_size.width; - let scrollable_height = info.scrollable_size.height; - - if scrollable_width > 0. { - info.offset.x = (new_offset.x).min(0.0).max(-scrollable_width); + match self.info { + SpatialTreeNodeInfo::Scroll(ref mut info) => { + let scrollable_size = info.scrollable_size(); + if scrollable_size.width > 0. { + info.offset.x = (new_offset.x).min(0.0).max(-scrollable_size.width); } - if scrollable_height > 0. { - info.offset.y = (new_offset.y).min(0.0).max(-scrollable_height); + if scrollable_size.height > 0. { + info.offset.y = (new_offset.y).min(0.0).max(-scrollable_size.height); } true }, @@ -125,9 +179,9 @@ impl ScrollTreeNode { &mut self, scroll_location: ScrollLocation, ) -> Option<(ExternalScrollId, LayoutVector2D)> { - let info = match self.scroll_info { - Some(ref mut data) => data, - None => return None, + let info = match self.info { + SpatialTreeNodeInfo::Scroll(ref mut info) => info, + _ => return None, }; if info.scroll_sensitivity.x != ScrollSensitivity::ScriptAndInputEvents && @@ -148,7 +202,7 @@ impl ScrollTreeNode { return Some((info.external_id, info.offset)); }, ScrollLocation::End => { - let end_pos = -info.scrollable_size.height; + let end_pos = -info.scrollable_size().height; if info.offset.y.round() <= end_pos { // Nothing to do on this layer. return None; @@ -159,20 +213,23 @@ impl ScrollTreeNode { }, }; - let scrollable_width = info.scrollable_size.width; - let scrollable_height = info.scrollable_size.height; + let scrollable_size = info.scrollable_size(); let original_layer_scroll_offset = info.offset; - if scrollable_width > 0. && + if scrollable_size.width > 0. && info.scroll_sensitivity.x == ScrollSensitivity::ScriptAndInputEvents { - info.offset.x = (info.offset.x + delta.x).min(0.0).max(-scrollable_width); + info.offset.x = (info.offset.x + delta.x) + .min(0.0) + .max(-scrollable_size.width); } - if scrollable_height > 0. && + if scrollable_size.height > 0. && info.scroll_sensitivity.y == ScrollSensitivity::ScriptAndInputEvents { - info.offset.y = (info.offset.y + delta.y).min(0.0).max(-scrollable_height); + info.offset.y = (info.offset.y + delta.y) + .min(0.0) + .max(-scrollable_size.height); } if info.offset != original_layer_scroll_offset { @@ -199,16 +256,23 @@ impl ScrollTree { pub fn add_scroll_tree_node( &mut self, parent: Option<&ScrollTreeNodeId>, - spatial_id: SpatialId, - scroll_info: Option<ScrollableNodeInfo>, + info: SpatialTreeNodeInfo, ) -> ScrollTreeNodeId { self.nodes.push(ScrollTreeNode { parent: parent.cloned(), - scroll_info, + webrender_id: None, + info, }); ScrollTreeNodeId { index: self.nodes.len() - 1, - spatial_id, + } + } + + /// Once WebRender display list construction is complete for this [`ScrollTree`], update + /// the mapping of nodes to WebRender [`SpatialId`]s. + pub fn update_mapping(&mut self, mapping: Vec<SpatialId>) { + for (spatial_id, node) in mapping.into_iter().zip(self.nodes.iter_mut()) { + node.webrender_id = Some(spatial_id); } } @@ -218,10 +282,16 @@ impl ScrollTree { } /// Get an immutable reference to the node with the given index. - pub fn get_node(&mut self, id: &ScrollTreeNodeId) -> &ScrollTreeNode { + pub fn get_node(&self, id: &ScrollTreeNodeId) -> &ScrollTreeNode { &self.nodes[id.index] } + /// Get the WebRender [`SpatialId`] for the given [`ScrollNodeId`]. This will + /// panic if [`ScrollTree::build_display_list`] has not been called yet. + pub fn webrender_id(&self, id: &ScrollTreeNodeId) -> SpatialId { + self.get_node(id).webrender_id() + } + /// Scroll the given scroll node on this scroll tree. If the node cannot be scrolled, /// because it isn't a scrollable node or it's already scrolled to the maximum scroll /// extent, try to scroll an ancestor of this node. Returns the node scrolled and the @@ -251,8 +321,10 @@ impl ScrollTree { offset: LayoutVector2D, ) -> bool { for node in self.nodes.iter_mut() { - match node.scroll_info { - Some(ref mut scroll_info) if scroll_info.external_id == external_scroll_id => { + match node.info { + SpatialTreeNodeInfo::Scroll(ref mut scroll_info) + if scroll_info.external_id == external_scroll_id => + { scroll_info.offset = offset; return true; }, @@ -320,15 +392,19 @@ impl CompositorDisplayListInfo { let mut scroll_tree = ScrollTree::default(); let root_reference_frame_id = scroll_tree.add_scroll_tree_node( None, - SpatialId::root_reference_frame(pipeline_id), - None, + SpatialTreeNodeInfo::ReferenceFrame(ReferenceFrameNodeInfo { + origin: Default::default(), + transform_style: TransformStyle::Flat, + transform: LayoutTransform::identity(), + kind: ReferenceFrameKind::default(), + }), ); let root_scroll_node_id = scroll_tree.add_scroll_tree_node( Some(&root_reference_frame_id), - SpatialId::root_scroll_node(pipeline_id), - Some(ScrollableNodeInfo { + SpatialTreeNodeInfo::Scroll(ScrollableNodeInfo { external_id: ExternalScrollId(0, pipeline_id), - scrollable_size: content_size - viewport_size, + content_rect: LayoutRect::from_origin_and_size(LayoutPoint::zero(), content_size), + clip_rect: LayoutRect::from_origin_and_size(LayoutPoint::zero(), viewport_size), scroll_sensitivity: viewport_scroll_sensitivity, offset: LayoutVector2D::zero(), }), diff --git a/components/shared/compositing/lib.rs b/components/shared/compositing/lib.rs index a6701ca2b52..061dfe023df 100644 --- a/components/shared/compositing/lib.rs +++ b/components/shared/compositing/lib.rs @@ -236,7 +236,7 @@ impl CrossProcessCompositorApi { pub fn send_display_list( &self, webview_id: WebViewId, - display_list_info: CompositorDisplayListInfo, + display_list_info: &CompositorDisplayListInfo, list: BuiltDisplayList, ) { let (display_list_data, display_list_descriptor) = list.into_data(); diff --git a/components/shared/compositing/tests/compositor.rs b/components/shared/compositing/tests/compositor.rs index 4d2ecfd99c9..e04f1770964 100644 --- a/components/shared/compositing/tests/compositor.rs +++ b/components/shared/compositing/tests/compositor.rs @@ -4,11 +4,12 @@ use base::id::ScrollTreeNodeId; use compositing_traits::display_list::{ - AxesScrollSensitivity, ScrollSensitivity, ScrollTree, ScrollableNodeInfo, + AxesScrollSensitivity, ScrollSensitivity, ScrollTree, ScrollableNodeInfo, SpatialTreeNodeInfo, + StickyNodeInfo, }; -use euclid::Size2D; +use euclid::{SideOffsets2D, Size2D}; use webrender_api::units::LayoutVector2D; -use webrender_api::{ExternalScrollId, PipelineId, ScrollLocation, SpatialId}; +use webrender_api::{ExternalScrollId, PipelineId, ScrollLocation, StickyOffsetBounds}; fn add_mock_scroll_node(tree: &mut ScrollTree) -> ScrollTreeNodeId { let pipeline_id = PipelineId(0, 0); @@ -16,7 +17,6 @@ fn add_mock_scroll_node(tree: &mut ScrollTree) -> ScrollTreeNodeId { let parent = if num_nodes > 0 { Some(ScrollTreeNodeId { index: num_nodes - 1, - spatial_id: SpatialId::new(num_nodes - 1, pipeline_id), }) } else { None @@ -24,10 +24,10 @@ fn add_mock_scroll_node(tree: &mut ScrollTree) -> ScrollTreeNodeId { tree.add_scroll_tree_node( parent.as_ref(), - SpatialId::new(num_nodes, pipeline_id), - Some(ScrollableNodeInfo { + SpatialTreeNodeInfo::Scroll(ScrollableNodeInfo { external_id: ExternalScrollId(num_nodes as u64, pipeline_id), - scrollable_size: Size2D::new(100.0, 100.0), + content_rect: Size2D::new(200.0, 200.0).into(), + clip_rect: Size2D::new(100.0, 100.0).into(), scroll_sensitivity: AxesScrollSensitivity { x: ScrollSensitivity::ScriptAndInputEvents, y: ScrollSensitivity::ScriptAndInputEvents, @@ -78,8 +78,15 @@ fn test_scroll_tree_simple_scroll_chaining() { let pipeline_id = PipelineId(0, 0); let parent_id = add_mock_scroll_node(&mut scroll_tree); - let unscrollable_child_id = - scroll_tree.add_scroll_tree_node(Some(&parent_id), SpatialId::new(1, pipeline_id), None); + let unscrollable_child_id = scroll_tree.add_scroll_tree_node( + Some(&parent_id), + SpatialTreeNodeInfo::Sticky(StickyNodeInfo { + frame_rect: Size2D::new(100.0, 100.0).into(), + margins: SideOffsets2D::default(), + vertical_offset_bounds: StickyOffsetBounds::new(0.0, 0.0), + horizontal_offset_bounds: StickyOffsetBounds::new(0.0, 0.0), + }), + ); let (scrolled_id, offset) = scroll_tree .scroll_node_or_ancestor( @@ -157,16 +164,14 @@ fn test_scroll_tree_chain_through_overflow_hidden() { let pipeline_id = PipelineId(0, 0); let parent_id = add_mock_scroll_node(&mut scroll_tree); let overflow_hidden_id = add_mock_scroll_node(&mut scroll_tree); - scroll_tree - .get_node_mut(&overflow_hidden_id) - .scroll_info - .as_mut() - .map(|info| { - info.scroll_sensitivity = AxesScrollSensitivity { - x: ScrollSensitivity::Script, - y: ScrollSensitivity::Script, - }; - }); + let node = scroll_tree.get_node_mut(&overflow_hidden_id); + + if let SpatialTreeNodeInfo::Scroll(ref mut scroll_node_info) = node.info { + scroll_node_info.scroll_sensitivity = AxesScrollSensitivity { + x: ScrollSensitivity::Script, + y: ScrollSensitivity::Script, + }; + } let (scrolled_id, offset) = scroll_tree .scroll_node_or_ancestor( |