Integrate stacking contexts into the display list

Integrate stacking contexts into the display list by adding two new
entry types, PushStackingContext and PopStackingContext. This allows us
to eliminate the ugly offsets map that DisplayList used to contain
and seems to speed up display list construction. With this approach
we are able to also completely prune pseudo-stacking contexts from the
final display list and remove their (minimal) overhead from display
list traversal Traversing the display list is also a bit simpler now.

Additionally, this will allow easier editing of the DisplayList to
properly support scrolling roots. The push/pop entries can be
duplicated to clone complex StackingContext trees between layers.
This commit is contained in:
Martin Robinson 2016-10-10 19:36:52 +02:00
parent b110eb394e
commit be62ad7117
4 changed files with 438 additions and 482 deletions

View file

@ -260,40 +260,32 @@ impl WebRenderStackingContextConverter for StackingContext {
builder: &mut webrender_traits::DisplayListBuilder,
frame_builder: &mut WebRenderFrameBuilder,
_force_positioned_stacking_level: bool) {
for child in self.children() {
while let Some(item) = traversal.advance(self) {
item.convert_to_webrender(builder, frame_builder);
}
while let Some(item) = traversal.next() {
match item {
&DisplayItem::PushStackingContextClass(ref stacking_context_item) => {
let stacking_context = &stacking_context_item.stacking_context;
debug_assert!(stacking_context.context_type == StackingContextType::Real);
if child.context_type == StackingContextType::Real {
let scroll_layer_id_for_children = if self.scrolls_overflow_area {
scroll_layer_id
} else {
None
};
let stacking_context_id = child.convert_to_webrender(traversal,
api,
pipeline_id,
epoch,
scroll_layer_id_for_children,
scroll_policy,
frame_builder);
builder.push_stacking_context(stacking_context_id);
} else {
child.convert_children_to_webrender(traversal,
api,
pipeline_id,
epoch,
scroll_layer_id,
scroll_policy,
builder,
frame_builder,
true);
}
}
let scroll_layer_id_for_children = if self.scrolls_overflow_area {
scroll_layer_id
} else {
None
};
while let Some(item) = traversal.advance(self) {
item.convert_to_webrender(builder, frame_builder);
let stacking_context_id =
stacking_context.convert_to_webrender(traversal,
api,
pipeline_id,
epoch,
scroll_layer_id_for_children,
scroll_policy,
frame_builder);
builder.push_stacking_context(stacking_context_id);
}
&DisplayItem::PopStackingContextClass(_) => return,
_ => item.convert_to_webrender(builder, frame_builder),
}
}
}
@ -359,19 +351,22 @@ impl WebRenderDisplayListConverter for DisplayList {
scroll_layer_id: Option<webrender_traits::ScrollLayerId>,
frame_builder: &mut WebRenderFrameBuilder)
-> webrender_traits::StackingContextId {
let mut traversal = DisplayListTraversal {
display_list: self,
current_item_index: 0,
last_item_index: self.list.len() - 1,
};
let mut traversal = DisplayListTraversal::new(self);
let item = traversal.next();
match item {
Some(&DisplayItem::PushStackingContextClass(ref stacking_context_item)) => {
let stacking_context = &stacking_context_item.stacking_context;
stacking_context.convert_to_webrender(&mut traversal,
api,
pipeline_id,
epoch,
scroll_layer_id,
ScrollPolicy::Scrollable,
frame_builder)
}
_ => unreachable!("DisplayList did not start with StackingContext."),
self.root_stacking_context.convert_to_webrender(&mut traversal,
api,
pipeline_id,
epoch,
scroll_layer_id,
ScrollPolicy::Scrollable,
frame_builder)
}
}
}
@ -513,6 +508,7 @@ impl WebRenderDisplayItemConverter for DisplayItem {
item.base.clip.to_clip_region(frame_builder),
pipeline_id);
}
DisplayItem::PushStackingContextClass(_) | DisplayItem::PopStackingContextClass(_) => {}
}
}
}