mirror of
https://github.com/servo/servo.git
synced 2025-09-30 00:29:14 +01:00
Changes function signatures to accept `ClipId`, `ExternalScrollId` and `ScrollTreeNodeId` instead of `&ClipId`, `&ExternalScrollId` and `&ScrollTreeNodeId`. This avoids several `&` and `*`. Testing: not needed, no behavior change. Signed-off-by: Oriol Brufau <obrufau@igalia.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
216 lines
7.5 KiB
Rust
216 lines
7.5 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
use std::cell::Cell;
|
|
|
|
use base::id::ScrollTreeNodeId;
|
|
use compositing_traits::display_list::{
|
|
AxesScrollSensitivity, ScrollTree, ScrollType, ScrollableNodeInfo, SpatialTreeNodeInfo,
|
|
};
|
|
use euclid::Size2D;
|
|
use webrender_api::units::LayoutVector2D;
|
|
use webrender_api::{ExternalScrollId, PipelineId, ScrollLocation};
|
|
|
|
fn add_mock_scroll_node(tree: &mut ScrollTree) -> (ScrollTreeNodeId, ExternalScrollId) {
|
|
let pipeline_id = PipelineId(0, 0);
|
|
let num_nodes = tree.nodes.len();
|
|
let parent = if num_nodes > 0 {
|
|
Some(ScrollTreeNodeId {
|
|
index: num_nodes - 1,
|
|
})
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let external_id = ExternalScrollId(num_nodes as u64, pipeline_id);
|
|
let scroll_node_id = tree.add_scroll_tree_node(
|
|
parent,
|
|
SpatialTreeNodeInfo::Scroll(ScrollableNodeInfo {
|
|
external_id,
|
|
content_rect: Size2D::new(200.0, 200.0).into(),
|
|
clip_rect: Size2D::new(100.0, 100.0).into(),
|
|
scroll_sensitivity: AxesScrollSensitivity {
|
|
x: ScrollType::Script | ScrollType::InputEvents,
|
|
y: ScrollType::Script | ScrollType::InputEvents,
|
|
},
|
|
offset: LayoutVector2D::zero(),
|
|
offset_changed: Cell::new(false),
|
|
}),
|
|
);
|
|
(scroll_node_id, external_id)
|
|
}
|
|
|
|
#[test]
|
|
fn test_scroll_tree_simple_scroll() {
|
|
let mut scroll_tree = ScrollTree::default();
|
|
let (id, external_id) = add_mock_scroll_node(&mut scroll_tree);
|
|
|
|
let (scrolled_id, offset) = scroll_tree
|
|
.scroll_node_or_ancestor(
|
|
external_id,
|
|
ScrollLocation::Delta(LayoutVector2D::new(20.0, 40.0)),
|
|
ScrollType::Script,
|
|
)
|
|
.unwrap();
|
|
let expected_offset = LayoutVector2D::new(20.0, 40.0);
|
|
assert_eq!(scrolled_id, external_id);
|
|
assert_eq!(offset, expected_offset);
|
|
assert_eq!(scroll_tree.get_node(id).offset(), Some(expected_offset));
|
|
|
|
let (scrolled_id, offset) = scroll_tree
|
|
.scroll_node_or_ancestor(
|
|
external_id,
|
|
ScrollLocation::Delta(LayoutVector2D::new(-20.0, -40.0)),
|
|
ScrollType::Script,
|
|
)
|
|
.unwrap();
|
|
let expected_offset = LayoutVector2D::new(0.0, 0.0);
|
|
assert_eq!(scrolled_id, external_id);
|
|
assert_eq!(offset, expected_offset);
|
|
assert_eq!(scroll_tree.get_node(id).offset(), Some(expected_offset));
|
|
|
|
// Scroll offsets must be positive.
|
|
let result = scroll_tree.scroll_node_or_ancestor(
|
|
external_id,
|
|
ScrollLocation::Delta(LayoutVector2D::new(-20.0, -40.0)),
|
|
ScrollType::Script,
|
|
);
|
|
assert!(result.is_none());
|
|
assert_eq!(
|
|
scroll_tree.get_node(id).offset(),
|
|
Some(LayoutVector2D::new(0.0, 0.0))
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_scroll_tree_simple_scroll_chaining() {
|
|
let mut scroll_tree = ScrollTree::default();
|
|
|
|
let pipeline_id = PipelineId(0, 0);
|
|
let (parent_id, parent_external_id) = add_mock_scroll_node(&mut scroll_tree);
|
|
|
|
let unscrollable_external_id = ExternalScrollId(100 as u64, pipeline_id);
|
|
let unscrollable_child_id = scroll_tree.add_scroll_tree_node(
|
|
Some(parent_id),
|
|
SpatialTreeNodeInfo::Scroll(ScrollableNodeInfo {
|
|
external_id: unscrollable_external_id,
|
|
content_rect: Size2D::new(100.0, 100.0).into(),
|
|
clip_rect: Size2D::new(100.0, 100.0).into(),
|
|
scroll_sensitivity: AxesScrollSensitivity {
|
|
x: ScrollType::Script | ScrollType::InputEvents,
|
|
y: ScrollType::Script | ScrollType::InputEvents,
|
|
},
|
|
offset: LayoutVector2D::zero(),
|
|
offset_changed: Cell::new(false),
|
|
}),
|
|
);
|
|
|
|
let (scrolled_id, offset) = scroll_tree
|
|
.scroll_node_or_ancestor(
|
|
unscrollable_external_id,
|
|
ScrollLocation::Delta(LayoutVector2D::new(20.0, 40.0)),
|
|
ScrollType::Script,
|
|
)
|
|
.unwrap();
|
|
let expected_offset = LayoutVector2D::new(20.0, 40.0);
|
|
assert_eq!(scrolled_id, parent_external_id);
|
|
assert_eq!(offset, expected_offset);
|
|
assert_eq!(
|
|
scroll_tree.get_node(parent_id).offset(),
|
|
Some(expected_offset)
|
|
);
|
|
|
|
let (scrolled_id, offset) = scroll_tree
|
|
.scroll_node_or_ancestor(
|
|
unscrollable_external_id,
|
|
ScrollLocation::Delta(LayoutVector2D::new(10.0, 15.0)),
|
|
ScrollType::Script,
|
|
)
|
|
.unwrap();
|
|
let expected_offset = LayoutVector2D::new(30.0, 55.0);
|
|
assert_eq!(scrolled_id, parent_external_id);
|
|
assert_eq!(offset, expected_offset);
|
|
assert_eq!(
|
|
scroll_tree.get_node(parent_id).offset(),
|
|
Some(expected_offset)
|
|
);
|
|
assert_eq!(
|
|
scroll_tree.get_node(unscrollable_child_id).offset(),
|
|
Some(LayoutVector2D::zero())
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_scroll_tree_chain_when_at_extent() {
|
|
let mut scroll_tree = ScrollTree::default();
|
|
|
|
let (parent_id, parent_external_id) = add_mock_scroll_node(&mut scroll_tree);
|
|
let (child_id, child_external_id) = add_mock_scroll_node(&mut scroll_tree);
|
|
|
|
let (scrolled_id, offset) = scroll_tree
|
|
.scroll_node_or_ancestor(child_external_id, ScrollLocation::End, ScrollType::Script)
|
|
.unwrap();
|
|
|
|
let expected_offset = LayoutVector2D::new(0.0, 100.0);
|
|
assert_eq!(scrolled_id, child_external_id);
|
|
assert_eq!(offset, expected_offset);
|
|
assert_eq!(
|
|
scroll_tree.get_node(child_id).offset(),
|
|
Some(expected_offset)
|
|
);
|
|
|
|
// The parent will have scrolled because the child is already at the extent
|
|
// of its scroll area in the y axis.
|
|
let (scrolled_id, offset) = scroll_tree
|
|
.scroll_node_or_ancestor(
|
|
child_external_id,
|
|
ScrollLocation::Delta(LayoutVector2D::new(0.0, 10.0)),
|
|
ScrollType::Script,
|
|
)
|
|
.unwrap();
|
|
let expected_offset = LayoutVector2D::new(0.0, 10.0);
|
|
assert_eq!(scrolled_id, parent_external_id);
|
|
assert_eq!(offset, expected_offset);
|
|
assert_eq!(
|
|
scroll_tree.get_node(parent_id).offset(),
|
|
Some(expected_offset)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_scroll_tree_chain_through_overflow_hidden() {
|
|
let mut scroll_tree = ScrollTree::default();
|
|
|
|
// Create a tree with a scrollable leaf, but make its `scroll_sensitivity`
|
|
// reflect `overflow: hidden` ie not responsive to non-script scroll events.
|
|
let (parent_id, parent_external_id) = add_mock_scroll_node(&mut scroll_tree);
|
|
let (overflow_hidden_id, overflow_hidden_external_id) = add_mock_scroll_node(&mut scroll_tree);
|
|
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: ScrollType::Script,
|
|
y: ScrollType::Script,
|
|
};
|
|
}
|
|
|
|
let (scrolled_id, offset) = scroll_tree
|
|
.scroll_node_or_ancestor(
|
|
overflow_hidden_external_id,
|
|
ScrollLocation::Delta(LayoutVector2D::new(20.0, 40.0)),
|
|
ScrollType::InputEvents,
|
|
)
|
|
.unwrap();
|
|
let expected_offset = LayoutVector2D::new(20.0, 40.0);
|
|
assert_eq!(scrolled_id, parent_external_id);
|
|
assert_eq!(offset, expected_offset);
|
|
assert_eq!(
|
|
scroll_tree.get_node(parent_id).offset(),
|
|
Some(expected_offset)
|
|
);
|
|
assert_eq!(
|
|
scroll_tree.get_node(overflow_hidden_id).offset(),
|
|
Some(LayoutVector2D::new(0.0, 0.0))
|
|
);
|
|
}
|