aboutsummaryrefslogtreecommitdiffstats
path: root/components/shared/compositing/display_list.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/shared/compositing/display_list.rs')
-rw-r--r--components/shared/compositing/display_list.rs154
1 files changed, 115 insertions, 39 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(),
}),