script: When using WebRender, keep the DOM-side scroll positions for

elements with `overflow: scroll` up to date, and take them into account
when doing hit testing.

Closes #11648.
This commit is contained in:
Patrick Walton 2016-06-08 18:46:02 -07:00
parent ce88b8ed30
commit 041cfe6d0a
14 changed files with 259 additions and 47 deletions

View file

@ -487,14 +487,15 @@ impl DisplayList {
/// Places all nodes containing the point of interest into `result`, topmost first. Respects
/// the `pointer-events` CSS property If `topmost_only` is true, stops after placing one node
/// into the list. `result` must be empty upon entry to this function.
pub fn hit_test(&self, point: Point2D<Au>) -> Vec<DisplayItemMetadata> {
pub fn hit_test(&self, point: &Point2D<Au>, scroll_offsets: &ScrollOffsetMap)
-> Vec<DisplayItemMetadata> {
let mut traversal = DisplayListTraversal {
display_list: self,
current_item_index: 0,
last_item_index: self.list.len() - 1,
};
let mut result = Vec::new();
self.root_stacking_context.hit_test(&mut traversal, point, &mut result);
self.root_stacking_context.hit_test(&mut traversal, point, scroll_offsets, &mut result);
result.reverse();
result
}
@ -610,24 +611,38 @@ impl StackingContext {
pub fn hit_test<'a>(&self,
traversal: &mut DisplayListTraversal<'a>,
point: Point2D<Au>,
point: &Point2D<Au>,
scroll_offsets: &ScrollOffsetMap,
result: &mut Vec<DisplayItemMetadata>) {
// Convert the point into stacking context local space
let point = if self.context_type == StackingContextType::Real {
let point = point - self.bounds.origin;
// Convert the point into stacking context local transform space.
let mut point = if self.context_type == StackingContextType::Real {
let point = *point - self.bounds.origin;
let inv_transform = self.transform.invert();
let frac_point = inv_transform.transform_point(&Point2D::new(point.x.to_f32_px(),
point.y.to_f32_px()));
Point2D::new(Au::from_f32_px(frac_point.x), Au::from_f32_px(frac_point.y))
} else {
point
*point
};
// Adjust the point to account for the scroll offset if necessary. This can only happen
// when WebRender is in use.
//
// We don't perform this adjustment on the root stacking context because the DOM-side code
// has already translated the point for us (e.g. in `Document::handle_mouse_move_event()`)
// by now.
if self.id != StackingContextId::root() {
if let Some(scroll_offset) = scroll_offsets.get(&self.id) {
point.x -= Au::from_f32_px(scroll_offset.x);
point.y -= Au::from_f32_px(scroll_offset.y);
}
}
for child in self.children.iter() {
while let Some(item) = traversal.advance(self) {
item.hit_test(point, result);
}
child.hit_test(traversal, point, result);
child.hit_test(traversal, &point, scroll_offsets, result);
}
while let Some(item) = traversal.advance(self) {
@ -1415,3 +1430,7 @@ impl WebRenderImageInfo {
}
}
}
/// The type of the scroll offset list. This is only populated if WebRender is in use.
pub type ScrollOffsetMap = HashMap<StackingContextId, Point2D<f32>>;