layout: Take into account the client point for fixed positioned stacking contexts.

This commit is contained in:
Emilio Cobos Álvarez 2016-08-08 12:00:14 -07:00
parent c420a870c1
commit 28d7c2dca8
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
7 changed files with 79 additions and 45 deletions

View file

@ -61,7 +61,7 @@ pub static BLUR_INFLATION_FACTOR: i32 = 3;
/// LayerInfo is used to store PaintLayer metadata during DisplayList construction.
/// It is also used for tracking LayerIds when creating layers to preserve ordering when
/// layered DisplayItems should render underneath unlayered DisplayItems.
#[derive(Clone, Copy, HeapSizeOf, Deserialize, Serialize)]
#[derive(Clone, Copy, HeapSizeOf, Deserialize, Serialize, Debug)]
pub struct LayerInfo {
/// The base LayerId of this layer.
pub layer_id: LayerId,
@ -133,7 +133,7 @@ impl<'a> DisplayListTraversal<'a> {
}
}
#[derive(HeapSizeOf, Deserialize, Serialize)]
#[derive(HeapSizeOf, Deserialize, Serialize, Debug)]
pub struct StackingContextOffsets {
pub start: u32,
pub block_backgrounds_and_borders: u32,
@ -508,9 +508,12 @@ impl DisplayList {
&draw_target, &stacking_context.filters, stacking_context.blend_mode);
}
/// Return all nodes containing the point of interest, bottommost first,
/// and respecting the `pointer-events` CSS property.
pub fn hit_test(&self, point: &Point2D<Au>, scroll_offsets: &ScrollOffsetMap)
/// Return all nodes containing the point of interest, bottommost first, and
/// respecting the `pointer-events` CSS property.
pub fn hit_test(&self,
translated_point: &Point2D<Au>,
client_point: &Point2D<Au>,
scroll_offsets: &ScrollOffsetMap)
-> Vec<DisplayItemMetadata> {
let mut traversal = DisplayListTraversal {
display_list: self,
@ -518,7 +521,11 @@ impl DisplayList {
last_item_index: self.list.len() - 1,
};
let mut result = Vec::new();
self.root_stacking_context.hit_test(&mut traversal, point, scroll_offsets, &mut result);
self.root_stacking_context.hit_test(&mut traversal,
translated_point,
client_point,
scroll_offsets,
&mut result);
result
}
}
@ -633,27 +640,35 @@ impl StackingContext {
pub fn hit_test<'a>(&self,
traversal: &mut DisplayListTraversal<'a>,
point: &Point2D<Au>,
translated_point: &Point2D<Au>,
client_point: &Point2D<Au>,
scroll_offsets: &ScrollOffsetMap,
result: &mut Vec<DisplayItemMetadata>) {
let is_fixed = match self.layer_info {
Some(ref layer_info) => layer_info.scroll_policy == ScrollPolicy::FixedPosition,
None => false,
};
let effective_point = if is_fixed { client_point } else { translated_point };
// 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 point = *effective_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
*effective_point
};
// Adjust the point to account for the scroll offset if necessary. This can only happen
// when WebRender is in use.
// Adjust the translated 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() {
// 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
// `Window::hit_test_query()`) by now.
if !is_fixed && 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);
@ -666,7 +681,7 @@ impl StackingContext {
result.push(meta);
}
}
child.hit_test(traversal, &point, scroll_offsets, result);
child.hit_test(traversal, translated_point, client_point, scroll_offsets, result);
}
while let Some(item) = traversal.advance(self) {
@ -1366,6 +1381,7 @@ impl DisplayItem {
// TODO(pcwalton): Use a precise algorithm here. This will allow us to properly hit
// test elements with `border-radius`, for example.
let base_item = self.base();
if !base_item.clip.might_intersect_point(&point) {
// Clipped out.
return None;