servo: Merge #7822 - Rework how StackingContexts are dynamically added to layers (from mrobinson:layer-info); r=pcwalton

StackingContexts are added to layers when it is necessary to maintain
their ordering on top of other layered StackingContexts. Instead of
tracking the information about a layer scattered around into different
structs, combine it all into LayerInfo. LayerInfo will be used in the
future to hold layer information for DisplayItems that are layerized
independently of StackingContexts.

Source-Repo: https://github.com/servo/servo
Source-Revision: 27d468b6674b81c396aa0a13d8fe9eb410c12d6e
This commit is contained in:
Martin Robinson 2015-10-05 23:05:21 -06:00
Родитель 78f3bda91c
Коммит 7845aaf33f
5 изменённых файлов: 162 добавлений и 115 удалений

Просмотреть файл

@ -76,6 +76,51 @@ impl OpaqueNode {
}
}
/// LayerInfo is used to store PaintLayer metadata during DisplayList construction.
/// It is also used for tracking LayerIds when creating layers to preserve ordering when
/// layered DisplayItems should render underneath unlayered DisplayItems.
#[derive(Clone, Copy, Debug, HeapSizeOf, Deserialize, Serialize)]
pub struct LayerInfo {
/// The base LayerId of this layer.
pub layer_id: LayerId,
/// The scroll policy of this layer.
pub scroll_policy: ScrollPolicy,
/// The subpage that this layer represents, if there is one.
pub subpage_layer_info: Option<SubpageLayerInfo>,
/// The id for the next layer in the sequence. This is used for synthesizing
/// layers for content that needs to be displayed on top of this layer.
pub next_layer_id: LayerId,
}
impl LayerInfo {
pub fn new(id: LayerId,
scroll_policy: ScrollPolicy,
subpage_layer_info: Option<SubpageLayerInfo>)
-> LayerInfo {
LayerInfo {
layer_id: id,
scroll_policy: scroll_policy,
subpage_layer_info: subpage_layer_info,
next_layer_id: id.companion_layer_id(),
}
}
fn next(&mut self) -> LayerInfo {
let new_layer_info = LayerInfo::new(self.next_layer_id, self.scroll_policy, None);
self.next_layer_id = self.next_layer_id.companion_layer_id();
new_layer_info
}
fn next_with_scroll_policy(&mut self, scroll_policy: ScrollPolicy) -> LayerInfo {
let mut new_layer_info = self.next();
new_layer_info.scroll_policy = scroll_policy;
new_layer_info
}
}
/// Display items that make up a stacking context. "Steps" here refer to the steps in CSS 2.1
/// Appendix E.
///
@ -474,15 +519,8 @@ pub struct StackingContext {
/// Whether this stacking context scrolls its overflow area.
pub scrolls_overflow_area: bool,
/// The scrolling policy of this stacking context, if it is promoted
/// to a layer.
pub scroll_policy: ScrollPolicy,
/// The layer id for this stacking context, if there is one.
pub layer_id: Option<LayerId>,
/// The subpage that this stacking context represents, if there is one.
pub subpage_layer_info: Option<SubpageLayerInfo>,
/// The layer info for this stacking context, if there is any.
pub layer_info: Option<LayerInfo>,
}
impl StackingContext {
@ -498,9 +536,7 @@ impl StackingContext {
perspective: Matrix4,
establishes_3d_context: bool,
scrolls_overflow_area: bool,
scroll_policy: ScrollPolicy,
layer_id: Option<LayerId>,
subpage_layer_info: Option<SubpageLayerInfo>)
layer_info: Option<LayerInfo>)
-> StackingContext {
let mut stacking_context = StackingContext {
display_list: display_list,
@ -513,16 +549,14 @@ impl StackingContext {
perspective: perspective,
establishes_3d_context: establishes_3d_context,
scrolls_overflow_area: scrolls_overflow_area,
scroll_policy: scroll_policy,
layer_id: layer_id,
subpage_layer_info: subpage_layer_info,
layer_info: layer_info,
};
StackingContextLayerCreator::add_layers_to_preserve_drawing_order(&mut stacking_context);
stacking_context
}
pub fn create_layered_child(&self,
layer_id: LayerId,
layer_info: LayerInfo,
display_list: Box<DisplayList>) -> StackingContext {
StackingContext {
display_list: display_list,
@ -535,9 +569,7 @@ impl StackingContext {
perspective: Matrix4::identity(),
establishes_3d_context: false,
scrolls_overflow_area: self.scrolls_overflow_area,
scroll_policy: self.scroll_policy,
layer_id: Some(layer_id),
subpage_layer_info: self.subpage_layer_info,
layer_info: Some(layer_info),
}
}
@ -569,7 +601,7 @@ impl StackingContext {
// If a layer is being used, the transform for this layer
// will be handled by the compositor.
let transform = match self.layer_id {
let transform = match self.layer_info {
Some(..) => *transform,
None => transform.mul(&self.transform),
};
@ -631,30 +663,37 @@ impl StackingContext {
}
fn print_with_tree(&self, print_tree: &mut PrintTree) {
if self.layer_id.is_some() {
if self.layer_info.is_some() {
print_tree.new_level(format!("Layered StackingContext at {:?} with overflow {:?}:",
self.bounds,
self.overflow));
self.bounds,
self.overflow));
} else {
print_tree.new_level(format!("StackingContext at {:?} with overflow {:?}:",
self.bounds,
self.overflow));
self.bounds,
self.overflow));
}
self.display_list.print_with_tree(print_tree);
print_tree.end_level();
}
fn scroll_policy(&self) -> ScrollPolicy {
match self.layer_info {
Some(ref layer_info) => layer_info.scroll_policy,
None => ScrollPolicy::Scrollable,
}
}
}
struct StackingContextLayerCreator {
display_list_for_next_layer: Option<Box<DisplayList>>,
all_following_children_need_layers: bool,
next_layer_info: Option<LayerInfo>,
}
impl StackingContextLayerCreator {
fn new() -> StackingContextLayerCreator {
StackingContextLayerCreator {
display_list_for_next_layer: None,
all_following_children_need_layers: false,
next_layer_info: None,
}
}
@ -673,55 +712,56 @@ impl StackingContextLayerCreator {
// 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.add_stacking_context(child_stacking_context, 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()
fn all_following_children_need_layers(&self) -> bool {
self.next_layer_info.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
.companion_layer_id();
let layer_info = self.next_layer_info.take().unwrap();
let child_stacking_context =
Arc::new(stacking_context.create_layered_child(next_layer_id, display_list));
Arc::new(stacking_context.create_layered_child(layer_info.clone(), display_list));
stacking_context.display_list.layered_children.push_back(
Arc::new(PaintLayer::new(next_layer_id,
Arc::new(PaintLayer::new(layer_info,
color::transparent(),
child_stacking_context,
ScrollPolicy::Scrollable)));
self.all_following_children_need_layers = true;
child_stacking_context)));
}
}
#[inline]
fn add_stacking_context(&mut self,
stacking_context: Arc<StackingContext>,
parent_stacking_context: &mut StackingContext) {
if let Some(layer_id) = stacking_context.layer_id {
if self.all_following_children_need_layers() || stacking_context.layer_info.is_some() {
self.add_layered_stacking_context(stacking_context, parent_stacking_context);
return;
}
parent_stacking_context.display_list.children.push_back(stacking_context);
}
fn add_layered_stacking_context(&mut self,
stacking_context: Arc<StackingContext>,
parent_stacking_context: &mut StackingContext) {
let layer_info = stacking_context.layer_info.clone();
if let Some(mut layer_info) = layer_info {
self.finish_building_current_layer(parent_stacking_context);
parent_stacking_context.display_list.layered_children.push_back(
Arc::new(PaintLayer::new(layer_id,
color::transparent(),
stacking_context,
ScrollPolicy::Scrollable)));
// 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;
self.next_layer_info =
Some(layer_info.next_with_scroll_policy(parent_stacking_context.scroll_policy()));
parent_stacking_context.display_list.layered_children.push_back(
Arc::new(PaintLayer::new_with_stacking_context(layer_info,
stacking_context,
color::transparent())));
return;
}

Просмотреть файл

@ -8,7 +8,7 @@ use app_units::Au;
use azure::AzFloat;
use azure::azure_hl::{BackendType, Color, DrawTarget, SurfaceFormat};
use canvas_traits::CanvasMsg;
use display_list::{self, StackingContext};
use display_list::{self, LayerInfo, StackingContext};
use euclid::Matrix4;
use euclid::point::Point2D;
use euclid::rect::Rect;
@ -19,7 +19,7 @@ use ipc_channel::ipc::IpcSender;
use layers::layers::{BufferRequest, LayerBuffer, LayerBufferSet};
use layers::platform::surface::{NativeDisplay, NativeSurface};
use msg::compositor_msg::{Epoch, FrameTreeId, LayerId, LayerKind, LayerProperties, PaintListener};
use msg::compositor_msg::{ScrollPolicy};
use msg::compositor_msg::{ScrollPolicy, SubpageLayerInfo};
use msg::constellation_msg::Msg as ConstellationMsg;
use msg::constellation_msg::PipelineExitType;
use msg::constellation_msg::{ConstellationChan, Failure, PipelineId};
@ -51,20 +51,36 @@ pub struct PaintLayer {
pub stacking_context: Arc<StackingContext>,
/// The scrolling policy of this layer.
pub scroll_policy: ScrollPolicy,
/// The subpage that this layer represents, if there is one.
pub subpage_layer_info: Option<SubpageLayerInfo>,
}
impl PaintLayer {
/// Creates a new `PaintLayer`.
pub fn new(id: LayerId,
pub fn new(layer_info: LayerInfo,
background_color: Color,
stacking_context: Arc<StackingContext>,
scroll_policy: ScrollPolicy)
stacking_context: Arc<StackingContext>)
-> PaintLayer {
PaintLayer {
id: id,
id: layer_info.layer_id,
background_color: background_color,
stacking_context: stacking_context,
scroll_policy: scroll_policy,
scroll_policy: layer_info.scroll_policy,
subpage_layer_info: layer_info.subpage_layer_info,
}
}
/// Creates a new `PaintLayer` with a stacking context.
pub fn new_with_stacking_context(layer_info: LayerInfo,
stacking_context: Arc<StackingContext>,
background_color: Color)
-> PaintLayer {
PaintLayer {
id: layer_info.layer_id,
background_color: background_color,
stacking_context: stacking_context,
scroll_policy: layer_info.scroll_policy,
subpage_layer_info: layer_info.subpage_layer_info,
}
}
@ -382,12 +398,12 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
parent_id: parent_id,
rect: layer_position,
background_color: paint_layer.background_color,
scroll_policy: paint_layer.stacking_context.scroll_policy,
scroll_policy: paint_layer.scroll_policy,
transform: transform,
perspective: perspective,
establishes_3d_context: paint_layer.stacking_context.establishes_3d_context,
scrolls_overflow_area: paint_layer.stacking_context.scrolls_overflow_area,
subpage_layer_info: paint_layer.stacking_context.subpage_layer_info,
subpage_layer_info: paint_layer.subpage_layer_info,
});
// When there is a new layer, the transforms and origin are handled by the compositor,

Просмотреть файл

@ -25,7 +25,7 @@ use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDisplayIte
use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion};
use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayList};
use gfx::display_list::{GradientDisplayItem};
use gfx::display_list::{GradientStop, ImageDisplayItem, LineDisplayItem};
use gfx::display_list::{GradientStop, ImageDisplayItem, LayerInfo, LineDisplayItem};
use gfx::display_list::{OpaqueNode, SolidColorDisplayItem};
use gfx::display_list::{StackingContext, TextDisplayItem, TextOrientation};
use gfx::paint_task::THREAD_TINT_COLORS;
@ -1279,32 +1279,6 @@ impl FragmentDisplayListBuilding for Fragment {
filters.push(Filter::Opacity(effects.opacity))
}
let canvas_or_iframe = match self.specific {
SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Iframe(_) => true,
_ => false
};
// There are three situations that need layers: when the fragment has the HAS_LAYER
// flag, when this is a canvas or iframe fragment, and when we are building a layer
// tree for overflow scrolling.
let layer_id = if mode == StackingContextCreationMode::InnerScrollWrapper {
Some(self.layer_id_for_overflow_scroll())
} else if self.flags.contains(HAS_LAYER) || canvas_or_iframe {
Some(self.layer_id())
} else {
None
};
// If it's a canvas we must propagate the layer and the renderer to the paint task.
if let SpecificFragmentInfo::Canvas(ref fragment_info) = self.specific {
let layer_id = layer_id.unwrap();
if let Some(ref ipc_renderer) = fragment_info.ipc_renderer {
layout_context.shared
.canvas_layers_sender
.send((layer_id, (*ipc_renderer.lock().unwrap()).clone())).unwrap();
}
}
let subpage_layer_info = match self.specific {
SpecificFragmentInfo::Iframe(ref iframe_fragment_info) => {
let border_padding = self.border_padding.to_physical(self.style().writing_mode);
@ -1317,6 +1291,34 @@ impl FragmentDisplayListBuilding for Fragment {
_ => None,
};
let canvas_or_iframe = match self.specific {
SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Iframe(_) => true,
_ => false
};
// There are three situations that need layers: when the fragment has the HAS_LAYER
// flag, when this is a canvas or iframe fragment, and when we are building a layer
// tree for overflow scrolling.
let layer_info = if mode == StackingContextCreationMode::InnerScrollWrapper {
Some(LayerInfo::new(self.layer_id_for_overflow_scroll(),
scroll_policy,
subpage_layer_info))
} else if self.flags.contains(HAS_LAYER) || canvas_or_iframe {
Some(LayerInfo::new(self.layer_id(), scroll_policy, subpage_layer_info))
} else {
None
};
// If it's a canvas we must propagate the layer and the renderer to the paint task.
if let SpecificFragmentInfo::Canvas(ref fragment_info) = self.specific {
let layer_id = layer_info.unwrap().layer_id;
if let Some(ref ipc_renderer) = fragment_info.ipc_renderer {
layout_context.shared
.canvas_layers_sender
.send((layer_id, (*ipc_renderer.lock().unwrap()).clone())).unwrap();
}
}
let scrolls_overflow_area = mode == StackingContextCreationMode::OuterScrollWrapper;
let transform_style = self.style().get_used_transform_style();
let establishes_3d_context = scrolls_overflow_area ||
@ -1332,9 +1334,7 @@ impl FragmentDisplayListBuilding for Fragment {
perspective,
establishes_3d_context,
scrolls_overflow_area,
scroll_policy,
layer_id,
subpage_layer_info))
layer_info))
}
fn clipping_region_for_children(&self,

Просмотреть файл

@ -27,8 +27,7 @@ use flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUti
use flow_ref::{self, FlowRef};
use fnv::FnvHasher;
use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
use gfx::display_list::StackingContext;
use gfx::display_list::{ClippingRegion, DisplayList, OpaqueNode};
use gfx::display_list::{ClippingRegion, DisplayList, LayerInfo, OpaqueNode, StackingContext};
use gfx::font_cache_task::FontCacheTask;
use gfx::font_context;
use gfx::paint_task::{LayoutToPaintMsg, PaintLayer};
@ -1119,7 +1118,6 @@ impl LayoutTask {
.add_to(&mut *display_list);
let origin = Rect::new(Point2D::new(Au(0), Au(0)), root_size);
let layer_id = layout_root.layer_id();
let stacking_context = Arc::new(StackingContext::new(display_list,
&origin,
&origin,
@ -1130,8 +1128,6 @@ impl LayoutTask {
Matrix4::identity(),
true,
false,
ScrollPolicy::Scrollable,
Some(layer_id),
None));
if opts::get().dump_display_list {
stacking_context.print("DisplayList".to_owned());
@ -1142,10 +1138,12 @@ impl LayoutTask {
rw_data.stacking_context = Some(stacking_context.clone());
let paint_layer = PaintLayer::new(layout_root.layer_id(),
root_background_color,
stacking_context,
ScrollPolicy::Scrollable);
let layer_info = LayerInfo::new(layout_root.layer_id(),
ScrollPolicy::Scrollable,
None);
let paint_layer = PaintLayer::new_with_stacking_context(layer_info,
stacking_context,
root_background_color);
debug!("Layout done!");

Просмотреть файл

@ -50,9 +50,9 @@ pub struct LayerId(
LayerType,
/// The identifier for this layer's fragment, derived from the fragment memory address.
usize,
/// Whether or not this layer is a companion layer, synthesized to ensure that
/// An index for identifying companion layers, synthesized to ensure that
/// content on top of this layer's fragment has the proper rendering order.
bool
usize
);
impl Debug for LayerId {
@ -65,30 +65,23 @@ impl Debug for LayerId {
LayerType::AfterPseudoContent => "-AfterPseudoContent",
};
let companion_string = if companion {
"-companion"
} else {
""
};
write!(f, "{}{}{}", id, type_string, companion_string)
write!(f, "{}{}-{}", id, type_string, companion)
}
}
impl LayerId {
/// FIXME(#2011, pcwalton): This is unfortunate. Maybe remove this in the future.
pub fn null() -> LayerId {
LayerId(LayerType::FragmentBody, 0, false)
LayerId(LayerType::FragmentBody, 0, 0)
}
pub fn new_of_type(layer_type: LayerType, fragment_id: usize) -> LayerId {
LayerId(layer_type, fragment_id, false)
LayerId(layer_type, fragment_id, 0)
}
pub fn companion_layer_id(&self) -> LayerId {
let LayerId(layer_type, id, companion) = *self;
assert!(!companion);
LayerId(layer_type, id, true)
LayerId(layer_type, id, companion + 1)
}
}
@ -172,7 +165,7 @@ pub enum ScriptToCompositorMsg {
}
/// Subpage (i.e. iframe)-specific information about each layer.
#[derive(Clone, Copy, Deserialize, Serialize, HeapSizeOf)]
#[derive(Clone, Copy, Debug, Deserialize, Serialize, HeapSizeOf)]
pub struct SubpageLayerInfo {
/// The ID of the pipeline.
pub pipeline_id: PipelineId,