Fix clip rect for iframes in hit testing code

Fixes #8080
This commit is contained in:
Matt Brubeck 2015-11-16 16:46:47 -08:00 committed by Paul Rouget
parent 4f625d3ab6
commit a61989e82b
2 changed files with 26 additions and 16 deletions

View file

@ -242,7 +242,9 @@ enum ShutdownState {
} }
struct HitTestResult { struct HitTestResult {
/// The topmost layer containing the requested point
layer: Rc<Layer<CompositorData>>, layer: Rc<Layer<CompositorData>>,
/// The point in client coordinates of the innermost window or frame containing `layer`
point: TypedPoint2D<LayerPixel, f32>, point: TypedPoint2D<LayerPixel, f32>,
} }
@ -1934,45 +1936,53 @@ impl<Window: WindowMethods> IOCompositor<Window> {
fn find_topmost_layer_at_point_for_layer(&self, fn find_topmost_layer_at_point_for_layer(&self,
layer: Rc<Layer<CompositorData>>, layer: Rc<Layer<CompositorData>>,
point: TypedPoint2D<LayerPixel, f32>, point_in_parent_layer: TypedPoint2D<LayerPixel, f32>,
clip_rect: &TypedRect<LayerPixel, f32>) clip_rect_in_parent_layer: &TypedRect<LayerPixel, f32>)
-> Option<HitTestResult> { -> Option<HitTestResult> {
let layer_bounds = *layer.bounds.borrow(); let layer_bounds = *layer.bounds.borrow();
let masks_to_bounds = *layer.masks_to_bounds.borrow(); let masks_to_bounds = *layer.masks_to_bounds.borrow();
if layer_bounds.is_empty() && masks_to_bounds { if layer_bounds.is_empty() && masks_to_bounds {
return None; return None;
} }
let scroll_offset = layer.extra_data.borrow().scroll_offset;
let clipped_layer_bounds = match clip_rect.intersection(&layer_bounds) { // Total offset from parent coordinates to this layer's coordinates.
// FIXME: This offset is incorrect for fixed-position layers.
let layer_offset = scroll_offset + layer_bounds.origin;
let clipped_layer_bounds = match clip_rect_in_parent_layer.intersection(&layer_bounds) {
Some(rect) => rect, Some(rect) => rect,
None => return None, None => return None,
}; };
let clip_rect_for_children = if masks_to_bounds { let clip_rect_for_children = if masks_to_bounds {
Rect::new(Point2D::zero(), clipped_layer_bounds.size) &clipped_layer_bounds
} else { } else {
clipped_layer_bounds.translate(&clip_rect.origin) clip_rect_in_parent_layer
}; }.translate(&-layer_offset);
let child_point = point - layer_bounds.origin; let child_point = point_in_parent_layer - layer_offset;
for child in layer.children().iter().rev() { for child in layer.children().iter().rev() {
// Translate the clip rect into the child's coordinate system. // Translate the clip rect into the child's coordinate system.
let clip_rect_for_child =
clip_rect_for_children.translate(&-*child.content_offset.borrow());
let result = self.find_topmost_layer_at_point_for_layer(child.clone(), let result = self.find_topmost_layer_at_point_for_layer(child.clone(),
child_point, child_point,
&clip_rect_for_child); &clip_rect_for_children);
if result.is_some() { if let Some(mut result) = result {
return result; // Return the point in layer coordinates of the topmost frame containing the point.
let pipeline_id = layer.extra_data.borrow().pipeline_id;
let child_pipeline_id = result.layer.extra_data.borrow().pipeline_id;
if pipeline_id == child_pipeline_id {
result.point = result.point + layer_offset;
}
return Some(result);
} }
} }
let point = point - *layer.content_offset.borrow(); if !clipped_layer_bounds.contains(&point_in_parent_layer) {
if !clipped_layer_bounds.contains(&point) {
return None; return None;
} }
return Some(HitTestResult { layer: layer, point: point }); return Some(HitTestResult { layer: layer, point: point_in_parent_layer });
} }
fn find_topmost_layer_at_point(&self, fn find_topmost_layer_at_point(&self,

View file

@ -121,7 +121,7 @@ pub trait CompositorLayer {
// Takes in a MouseWindowEvent, determines if it should be passed to children, and // Takes in a MouseWindowEvent, determines if it should be passed to children, and
// sends the event off to the appropriate pipeline. NB: the cursor position is in // sends the event off to the appropriate pipeline. NB: the cursor position is in
// page coordinates. // client coordinates.
fn send_mouse_event<Window>(&self, fn send_mouse_event<Window>(&self,
compositor: &IOCompositor<Window>, compositor: &IOCompositor<Window>,
event: MouseWindowEvent, event: MouseWindowEvent,