servo: Merge #7563 - Layerize StackingContexts that are on top of layers (from mrobinson:layerize-stacking-contexts); r=pcwalton
StackingContexts that should be painted on top of StackingContexts that are already layerized should automatically get their own layer. This will ensure proper painting order. Source-Repo: https://github.com/servo/servo Source-Revision: c0381c732569b9abe6282c6c750533bc271a2019
This commit is contained in:
@@ -36,6 +36,7 @@ use paint_task::PaintLayer;
|
||||
use smallvec::SmallVec;
|
||||
use std::collections::linked_list::{self, LinkedList};
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::slice::Iter;
|
||||
use std::sync::Arc;
|
||||
use style::computed_values::{border_style, cursor, filter, image_rendering, mix_blend_mode};
|
||||
@@ -304,7 +305,7 @@ pub struct StackingContext {
|
||||
impl StackingContext {
|
||||
/// Creates a new stacking context.
|
||||
#[inline]
|
||||
pub fn new(mut display_list: Box<DisplayList>,
|
||||
pub fn new(display_list: Box<DisplayList>,
|
||||
bounds: &Rect<Au>,
|
||||
overflow: &Rect<Au>,
|
||||
z_index: i32,
|
||||
@@ -317,8 +318,7 @@ impl StackingContext {
|
||||
scroll_policy: ScrollPolicy,
|
||||
layer_id: Option<LayerId>)
|
||||
-> StackingContext {
|
||||
display_list.sort_and_layerize_children();
|
||||
StackingContext {
|
||||
let mut stacking_context = StackingContext {
|
||||
display_list: display_list,
|
||||
bounds: *bounds,
|
||||
overflow: *overflow,
|
||||
@@ -331,6 +331,27 @@ impl StackingContext {
|
||||
scrolls_overflow_area: scrolls_overflow_area,
|
||||
scroll_policy: scroll_policy,
|
||||
layer_id: layer_id,
|
||||
};
|
||||
StackingContextLayerCreator::add_layers_to_preserve_drawing_order(&mut stacking_context);
|
||||
stacking_context
|
||||
}
|
||||
|
||||
pub fn create_layered_child(&self,
|
||||
layer_id: LayerId,
|
||||
display_list: Box<DisplayList>) -> StackingContext {
|
||||
StackingContext {
|
||||
display_list: display_list,
|
||||
bounds: self.bounds.clone(),
|
||||
overflow: self.overflow.clone(),
|
||||
z_index: self.z_index,
|
||||
filters: self.filters.clone(),
|
||||
blend_mode: self.blend_mode,
|
||||
transform: Matrix4::identity(),
|
||||
perspective: Matrix4::identity(),
|
||||
establishes_3d_context: false,
|
||||
scrolls_overflow_area: self.scrolls_overflow_area,
|
||||
scroll_policy: self.scroll_policy,
|
||||
layer_id: Some(layer_id),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,6 +667,84 @@ impl StackingContext {
|
||||
}
|
||||
}
|
||||
|
||||
struct StackingContextLayerCreator {
|
||||
display_list_for_next_layer: Option<Box<DisplayList>>,
|
||||
all_following_children_need_layers: bool,
|
||||
}
|
||||
|
||||
impl StackingContextLayerCreator {
|
||||
fn new() -> StackingContextLayerCreator {
|
||||
StackingContextLayerCreator {
|
||||
display_list_for_next_layer: None,
|
||||
all_following_children_need_layers: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn add_layers_to_preserve_drawing_order(stacking_context: &mut StackingContext) {
|
||||
let mut state = StackingContextLayerCreator::new();
|
||||
|
||||
// First we need to sort child stacking contexts by z-index, so we can detect
|
||||
// situations where unlayered ones should be on top of layered ones.
|
||||
let existing_children = mem::replace(&mut stacking_context.display_list.children,
|
||||
LinkedList::new());
|
||||
let mut sorted_children: SmallVec<[Arc<StackingContext>; 8]> = SmallVec::new();
|
||||
sorted_children.extend(existing_children.into_iter());
|
||||
sorted_children.sort_by(|this, other| this.z_index.cmp(&other.z_index));
|
||||
|
||||
// FIXME(#7566, mrobinson): This should properly handle unlayered children that are on
|
||||
// top of unlayered children which have child stacking contexts with layers.
|
||||
for child_stacking_context in sorted_children.into_iter() {
|
||||
if state.stacking_context_needs_layer(&child_stacking_context) {
|
||||
state.add_stacking_context(child_stacking_context, stacking_context);
|
||||
} else {
|
||||
stacking_context.display_list.children.push_back(child_stacking_context);
|
||||
}
|
||||
}
|
||||
state.finish_building_current_layer(stacking_context);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn stacking_context_needs_layer(&mut self, stacking_context: &Arc<StackingContext>) -> bool {
|
||||
self.all_following_children_need_layers || stacking_context.layer_id.is_some()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn finish_building_current_layer(&mut self, stacking_context: &mut StackingContext) {
|
||||
if let Some(display_list) = self.display_list_for_next_layer.take() {
|
||||
let next_layer_id =
|
||||
stacking_context.display_list.layered_children.back().unwrap().id.next_layer_id();
|
||||
let child_stacking_context =
|
||||
Arc::new(stacking_context.create_layered_child(next_layer_id, display_list));
|
||||
stacking_context.display_list.layered_children.push_back(
|
||||
PaintLayer::new(next_layer_id, color::transparent(), child_stacking_context));
|
||||
self.all_following_children_need_layers = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn add_stacking_context(&mut self,
|
||||
stacking_context: Arc<StackingContext>,
|
||||
parent_stacking_context: &mut StackingContext) {
|
||||
if let Some(layer_id) = stacking_context.layer_id {
|
||||
self.finish_building_current_layer(parent_stacking_context);
|
||||
parent_stacking_context.display_list.layered_children.push_back(
|
||||
PaintLayer::new(layer_id, color::transparent(), stacking_context));
|
||||
|
||||
// We have started processing layered stacking contexts, so any stacking context that
|
||||
// we process from now on needs its own layer to ensure proper rendering order.
|
||||
self.all_following_children_need_layers = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if self.display_list_for_next_layer.is_none() {
|
||||
self.display_list_for_next_layer = Some(box DisplayList::new());
|
||||
}
|
||||
if let Some(ref mut display_list) = self.display_list_for_next_layer {
|
||||
display_list.children.push_back(stacking_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the stacking context in the given tree of stacking contexts with a specific layer ID.
|
||||
pub fn find_stacking_context_with_layer_id(this: &Arc<StackingContext>, layer_id: LayerId)
|
||||
-> Option<Arc<StackingContext>> {
|
||||
|
||||
@@ -2058,7 +2058,7 @@ impl Flow for BlockFlow {
|
||||
// FIXME(#2010, pcwalton): This is a hack and is totally bogus in the presence of pseudo-
|
||||
// elements. But until we have incremental reflow we can't do better--we recreate the flow
|
||||
// for every DOM node so otherwise we nuke layers on every reflow.
|
||||
LayerId(self.fragment.node.id() as usize, fragment_index)
|
||||
LayerId(self.fragment.node.id() as usize, fragment_index, 0)
|
||||
}
|
||||
|
||||
fn is_absolute_containing_block(&self) -> bool {
|
||||
|
||||
@@ -361,7 +361,7 @@ pub trait Flow: fmt::Debug + Sync + Send + 'static {
|
||||
#[allow(unsafe_code)]
|
||||
fn layer_id(&self, fragment_id: u32) -> LayerId {
|
||||
let obj = unsafe { mem::transmute::<&&Self, &raw::TraitObject>(&self) };
|
||||
LayerId(obj.data as usize, fragment_id)
|
||||
LayerId(obj.data as usize, fragment_id, 0)
|
||||
}
|
||||
|
||||
/// Attempts to perform incremental fixup of this flow by replacing its fragment's style with
|
||||
|
||||
@@ -36,19 +36,35 @@ impl FrameTreeId {
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Copy, Hash, Deserialize, Serialize, HeapSizeOf)]
|
||||
pub struct LayerId(pub usize, pub u32);
|
||||
pub struct LayerId(
|
||||
/// A base layer ID, currently derived from DOM element pointer address.
|
||||
pub usize,
|
||||
|
||||
/// FIXME(#2010, pcwalton): A marker for overflow scroll layers.
|
||||
pub u32,
|
||||
|
||||
/// A sub ID, which is used for synthesizing new layers for content that
|
||||
/// belongs on top of this layer. This prevents accidentally making colliding
|
||||
/// layer ids.
|
||||
pub u32
|
||||
);
|
||||
|
||||
impl Debug for LayerId {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let LayerId(a, b) = *self;
|
||||
write!(f, "Layer({}, {})", a, b)
|
||||
let LayerId(a, b, c) = *self;
|
||||
write!(f, "Layer({}, {}, {})", a, b, c)
|
||||
}
|
||||
}
|
||||
|
||||
impl LayerId {
|
||||
/// FIXME(#2011, pcwalton): This is unfortunate. Maybe remove this in the future.
|
||||
pub fn null() -> LayerId {
|
||||
LayerId(0, 0)
|
||||
LayerId(0, 0, 0)
|
||||
}
|
||||
|
||||
pub fn next_layer_id(&self) -> LayerId {
|
||||
let LayerId(a, b, sub_id) = *self;
|
||||
LayerId(a, b, sub_id + 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user