Auto merge of #11900 - Ms2ger:displaylist-cleanup, r=nox

Various DisplayList cleanup.

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/11900)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-06-29 03:32:52 -05:00 committed by GitHub
commit ffb8b35d35
3 changed files with 23 additions and 33 deletions

View file

@ -215,13 +215,8 @@ pub struct DisplayList {
impl DisplayList { impl DisplayList {
pub fn new(mut root_stacking_context: StackingContext, pub fn new(mut root_stacking_context: StackingContext,
items: &mut Option<Vec<DisplayItem>>) items: Vec<DisplayItem>)
-> DisplayList { -> DisplayList {
let items = match items.take() {
Some(items) => items,
None => panic!("Tried to create empty display list."),
};
let mut offsets = FnvHashMap(HashMap::with_hasher(Default::default())); let mut offsets = FnvHashMap(HashMap::with_hasher(Default::default()));
DisplayList::sort_and_count_stacking_contexts(&mut root_stacking_context, &mut offsets, 0); DisplayList::sort_and_count_stacking_contexts(&mut root_stacking_context, &mut offsets, 0);
@ -485,9 +480,8 @@ impl DisplayList {
&draw_target, &stacking_context.filters, stacking_context.blend_mode); &draw_target, &stacking_context.filters, stacking_context.blend_mode);
} }
/// Places all nodes containing the point of interest into `result`, topmost first. Respects /// Return all nodes containing the point of interest, bottommost first,
/// the `pointer-events` CSS property If `topmost_only` is true, stops after placing one node /// and respecting the `pointer-events` CSS property.
/// into the list. `result` must be empty upon entry to this function.
pub fn hit_test(&self, point: &Point2D<Au>, scroll_offsets: &ScrollOffsetMap) pub fn hit_test(&self, point: &Point2D<Au>, scroll_offsets: &ScrollOffsetMap)
-> Vec<DisplayItemMetadata> { -> Vec<DisplayItemMetadata> {
let mut traversal = DisplayListTraversal { let mut traversal = DisplayListTraversal {
@ -497,7 +491,6 @@ impl DisplayList {
}; };
let mut result = Vec::new(); 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, point, scroll_offsets, &mut result);
result.reverse();
result result
} }
} }
@ -641,13 +634,17 @@ impl StackingContext {
for child in self.children.iter() { for child in self.children.iter() {
while let Some(item) = traversal.advance(self) { while let Some(item) = traversal.advance(self) {
item.hit_test(point, result); if let Some(meta) = item.hit_test(point) {
result.push(meta);
}
} }
child.hit_test(traversal, &point, scroll_offsets, result); child.hit_test(traversal, &point, scroll_offsets, result);
} }
while let Some(item) = traversal.advance(self) { while let Some(item) = traversal.advance(self) {
item.hit_test(point, result); if let Some(meta) = item.hit_test(point) {
result.push(meta);
}
} }
} }
@ -1336,21 +1333,21 @@ impl DisplayItem {
println!("{}+ {:?}", indent, self); println!("{}+ {:?}", indent, self);
} }
fn hit_test(&self, point: Point2D<Au>, result: &mut Vec<DisplayItemMetadata>) { fn hit_test(&self, point: Point2D<Au>) -> Option<DisplayItemMetadata> {
// TODO(pcwalton): Use a precise algorithm here. This will allow us to properly hit // TODO(pcwalton): Use a precise algorithm here. This will allow us to properly hit
// test elements with `border-radius`, for example. // test elements with `border-radius`, for example.
let base_item = self.base(); let base_item = self.base();
if !base_item.clip.might_intersect_point(&point) { if !base_item.clip.might_intersect_point(&point) {
// Clipped out. // Clipped out.
return; return None;
} }
if !self.bounds().contains(&point) { if !self.bounds().contains(&point) {
// Can't possibly hit. // Can't possibly hit.
return; return None;
} }
if base_item.metadata.pointing.is_none() { if base_item.metadata.pointing.is_none() {
// `pointer-events` is `none`. Ignore this item. // `pointer-events` is `none`. Ignore this item.
return; return None;
} }
match *self { match *self {
@ -1369,18 +1366,17 @@ impl DisplayItem {
(border.border_widths.top + (border.border_widths.top +
border.border_widths.bottom))); border.border_widths.bottom)));
if interior_rect.contains(&point) { if interior_rect.contains(&point) {
return; return None;
} }
} }
DisplayItem::BoxShadowClass(_) => { DisplayItem::BoxShadowClass(_) => {
// Box shadows can never be hit. // Box shadows can never be hit.
return return None;
} }
_ => {} _ => {}
} }
// We found a hit! Some(base_item.metadata)
result.push(base_item.metadata);
} }
} }

View file

@ -150,6 +150,7 @@ impl LayoutRPC for LayoutRPCImpl {
}; };
nodes_from_point_list.iter() nodes_from_point_list.iter()
.rev()
.map(|metadata| metadata.node.to_untrusted_node_address()) .map(|metadata| metadata.node.to_untrusted_node_address())
.collect() .collect()
} }

View file

@ -918,8 +918,7 @@ impl LayoutThread {
root_background_color)); root_background_color));
rw_data.display_list = rw_data.display_list =
Some(Arc::new(DisplayList::new(root_stacking_context, Some(Arc::new(DisplayList::new(root_stacking_context, display_list_entries)))
&mut Some(display_list_entries))))
} }
if data.goal == ReflowGoal::ForDisplay { if data.goal == ReflowGoal::ForDisplay {
@ -1157,17 +1156,11 @@ impl LayoutThread {
}, },
ReflowQueryType::HitTestQuery(point, update_cursor) => { ReflowQueryType::HitTestQuery(point, update_cursor) => {
let point = Point2D::new(Au::from_f32_px(point.x), Au::from_f32_px(point.y)); let point = Point2D::new(Au::from_f32_px(point.x), Au::from_f32_px(point.y));
let result = match rw_data.display_list { let result = rw_data.display_list
None => panic!("Tried to hit test with no display list"), .as_ref()
Some(ref display_list) => { .expect("Tried to hit test with no display list")
display_list.hit_test(&point, &rw_data.stacking_context_scroll_offsets) .hit_test(&point, &rw_data.stacking_context_scroll_offsets);
} rw_data.hit_test_response = (result.last().cloned(), update_cursor);
};
rw_data.hit_test_response = if result.len() > 0 {
(Some(result[0]), update_cursor)
} else {
(None, update_cursor)
};
}, },
ReflowQueryType::NodeGeometryQuery(node) => { ReflowQueryType::NodeGeometryQuery(node) => {
let node = unsafe { ServoLayoutNode::new(&node) }; let node = unsafe { ServoLayoutNode::new(&node) };