Mix stacking contexts into the positioned content list

Sometimes positioned content needs to be layered on top of stacking
contexts. The layer synthesis code can do this, but the current design
prevents it because stacking contexts are stored in a separate struct
member. In order to preserve tree order, mix stacking contexts into the
positioned content list, by adding a new StackingContextClass
DisplayItem. Such items do not have a base DisplayItem.

In some ways this simplifies the code, because we no longer have to
have a separate code path in the StackingContextLayerCreator.

Fixes #7779.
Fixes #7983.
Fixes #8122.
Fixes #8310.
This commit is contained in:
Martin Robinson 2015-10-13 17:29:29 -07:00
parent 5c11c88e92
commit c1a38e240a
13 changed files with 330 additions and 295 deletions

View file

@ -40,7 +40,6 @@ impl DisplayListOptimizer {
display_list.positioned_content.iter());
self.add_in_bounds_display_items(&mut result.outlines,
display_list.outlines.iter());
self.add_in_bounds_stacking_contexts(&mut result.children, display_list.children.iter());
result
}
@ -50,39 +49,49 @@ impl DisplayListOptimizer {
display_items: I)
where I: Iterator<Item=&'a DisplayItem> {
for display_item in display_items {
if self.visible_rect.intersects(&display_item.base().bounds) &&
display_item.base().clip.might_intersect_rect(&self.visible_rect) {
result_list.push_back((*display_item).clone())
if !self.should_include_display_item(display_item) {
continue;
}
result_list.push_back((*display_item).clone())
}
}
/// Adds child stacking contexts whose boundaries intersect the visible rect to `result_list`.
fn add_in_bounds_stacking_contexts<'a, I>(&self,
result_list: &mut LinkedList<Arc<StackingContext>>,
stacking_contexts: I)
where I: Iterator<Item=&'a Arc<StackingContext>> {
for stacking_context in stacking_contexts {
// Transform this stacking context to get it into the same space as
// the parent stacking context.
let origin_x = stacking_context.bounds.origin.x.to_f32_px();
let origin_y = stacking_context.bounds.origin.y.to_f32_px();
fn should_include_display_item(&self, item: &DisplayItem) -> bool {
if let &DisplayItem::StackingContextClass(ref stacking_context) = item {
return self.should_include_stacking_context(stacking_context);
}
let transform = Matrix4::identity().translate(origin_x,
origin_y,
0.0)
.mul(&stacking_context.transform);
let transform_2d = Matrix2D::new(transform.m11, transform.m12,
transform.m21, transform.m22,
transform.m41, transform.m42);
if !self.visible_rect.intersects(&item.bounds()) {
return false;
}
let overflow = geometry::au_rect_to_f32_rect(stacking_context.overflow);
let overflow = transform_2d.transform_rect(&overflow);
let overflow = geometry::f32_rect_to_au_rect(overflow);
if self.visible_rect.intersects(&overflow) {
result_list.push_back((*stacking_context).clone())
if let Some(base_item) = item.base() {
if !base_item.clip.might_intersect_rect(&self.visible_rect) {
return false;
}
}
true
}
fn should_include_stacking_context(&self, stacking_context: &Arc<StackingContext>) -> bool {
// Transform this stacking context to get it into the same space as
// the parent stacking context.
let origin_x = stacking_context.bounds.origin.x.to_f32_px();
let origin_y = stacking_context.bounds.origin.y.to_f32_px();
let transform = Matrix4::identity().translate(origin_x,
origin_y,
0.0)
.mul(&stacking_context.transform);
let transform_2d = Matrix2D::new(transform.m11, transform.m12,
transform.m21, transform.m22,
transform.m41, transform.m42);
let overflow = geometry::au_rect_to_f32_rect(stacking_context.overflow);
let overflow = transform_2d.transform_rect(&overflow);
let overflow = geometry::f32_rect_to_au_rect(overflow);
self.visible_rect.intersects(&overflow)
}
}