Auto merge of #7950 - mrobinson:layerize-iframes, r=pcwalton

Integrate iframes into the display list

Instead of always promoting iframes to StackingContexts, integrate them
into the display list. This prevents stacking bugs when
non-stacking-context elements should be drawn on top of iframes.

To accomplish this, we add another step to ordering layer creation,
where LayeredItems in the DisplayList are added to layers described by
the LayerInfo structures collected at the end of the DisplayList.
Unlayered items that follow these layered items are added to
synthesized layers.

Another result of this change is that iframe layers can be positioned
directly at the location of the iframe fragment, eliminating the need
for the SubpageLayerInfo struct entirely.

Iframes are the first type of content treated this way, but this change
opens up the possibility to properly order canvas and all other layered
content that does not create a stacking context.

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/7950)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2015-10-20 16:01:38 -06:00
commit 11d23a41b3
13 changed files with 271 additions and 91 deletions

View file

@ -23,7 +23,8 @@ use euclid::num::Zero;
use euclid::{Matrix2D, Matrix4, Point2D, Rect, SideOffsets2D, Size2D};
use gfx_traits::color;
use libc::uintptr_t;
use msg::compositor_msg::{LayerId, LayerKind, ScrollPolicy, SubpageLayerInfo};
use msg::compositor_msg::{LayerId, LayerKind, ScrollPolicy};
use msg::constellation_msg::PipelineId;
use net_traits::image::base::Image;
use paint_context::PaintContext;
use paint_task::{PaintLayerContents, PaintLayer};
@ -88,7 +89,7 @@ pub struct LayerInfo {
pub scroll_policy: ScrollPolicy,
/// The subpage that this layer represents, if there is one.
pub subpage_layer_info: Option<SubpageLayerInfo>,
pub subpage_pipeline_id: Option<PipelineId>,
/// 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.
@ -98,12 +99,12 @@ pub struct LayerInfo {
impl LayerInfo {
pub fn new(id: LayerId,
scroll_policy: ScrollPolicy,
subpage_layer_info: Option<SubpageLayerInfo>)
subpage_pipeline_id: Option<PipelineId>)
-> LayerInfo {
LayerInfo {
layer_id: id,
scroll_policy: scroll_policy,
subpage_layer_info: subpage_layer_info,
subpage_pipeline_id: subpage_pipeline_id,
next_layer_id: id.companion_layer_id(),
}
}
@ -144,6 +145,8 @@ pub struct DisplayList {
pub children: LinkedList<Arc<StackingContext>>,
/// Child PaintLayers that will be rendered on top of everything else.
pub layered_children: LinkedList<Arc<PaintLayer>>,
/// Information about child layers.
pub layer_info: LinkedList<LayerInfo>,
}
impl DisplayList {
@ -159,6 +162,7 @@ impl DisplayList {
outlines: LinkedList::new(),
children: LinkedList::new(),
layered_children: LinkedList::new(),
layer_info: LinkedList::new(),
}
}
@ -174,6 +178,7 @@ impl DisplayList {
self.outlines.append(&mut other.outlines);
self.children.append(&mut other.children);
self.layered_children.append(&mut other.layered_children);
self.layer_info.append(&mut other.layer_info);
}
/// Merges all display items from all non-float stacking levels to the `float` stacking level.
@ -554,6 +559,29 @@ impl DisplayList {
bounds
}
#[inline]
fn get_section_mut(&mut self, section: DisplayListSection) -> &mut LinkedList<DisplayItem> {
match section {
DisplayListSection::BackgroundAndBorders => &mut self.background_and_borders,
DisplayListSection::BlockBackgroundsAndBorders =>
&mut self.block_backgrounds_and_borders,
DisplayListSection::Floats => &mut self.floats,
DisplayListSection::Content => &mut self.content,
DisplayListSection::PositionedContent => &mut self.positioned_content,
DisplayListSection::Outlines => &mut self.outlines,
}
}
}
#[derive(Clone, Copy, Debug)]
enum DisplayListSection {
BackgroundAndBorders,
BlockBackgroundsAndBorders,
Floats,
Content,
PositionedContent,
Outlines,
}
#[derive(HeapSizeOf, Deserialize, Serialize)]
@ -591,6 +619,9 @@ pub struct StackingContext {
/// The layer info for this stacking context, if there is any.
pub layer_info: Option<LayerInfo>,
/// The LayerId of the last child layer of this stacking context.
pub last_child_layer_info: Option<LayerInfo>,
}
impl StackingContext {
@ -620,29 +651,12 @@ impl StackingContext {
establishes_3d_context: establishes_3d_context,
scrolls_overflow_area: scrolls_overflow_area,
layer_info: layer_info,
last_child_layer_info: None,
};
StackingContextLayerCreator::add_layers_to_preserve_drawing_order(&mut stacking_context);
stacking_context
}
pub fn create_layered_child(&self,
layer_info: LayerInfo,
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,
layer_info: Some(layer_info),
}
}
/// Draws the stacking context in the proper order according to the steps in CSS 2.1 § E.2.
pub fn draw_into_context(&self,
display_list: &DisplayList,
@ -752,11 +766,22 @@ impl StackingContext {
None => ScrollPolicy::Scrollable,
}
}
fn get_layer_info(&mut self, layer_id: LayerId) -> &mut LayerInfo {
for layer_info in self.display_list.layer_info.iter_mut() {
if layer_info.layer_id == layer_id {
return layer_info;
}
}
panic!("Could not find LayerInfo with id: {:?}", layer_id);
}
}
struct StackingContextLayerCreator {
display_list_for_next_layer: Option<DisplayList>,
next_layer_info: Option<LayerInfo>,
building_ordering_layer: bool,
}
impl StackingContextLayerCreator {
@ -764,6 +789,7 @@ impl StackingContextLayerCreator {
StackingContextLayerCreator {
display_list_for_next_layer: None,
next_layer_info: None,
building_ordering_layer: false,
}
}
@ -771,6 +797,15 @@ impl StackingContextLayerCreator {
fn add_layers_to_preserve_drawing_order(stacking_context: &mut StackingContext) {
let mut state = StackingContextLayerCreator::new();
state.layerize_display_list_section(DisplayListSection::BackgroundAndBorders,
stacking_context);
state.layerize_display_list_section(DisplayListSection::BlockBackgroundsAndBorders,
stacking_context);
state.layerize_display_list_section(DisplayListSection::Floats, stacking_context);
state.layerize_display_list_section(DisplayListSection::Content, stacking_context);
state.layerize_display_list_section(DisplayListSection::PositionedContent, stacking_context);
state.layerize_display_list_section(DisplayListSection::Outlines, stacking_context);
// 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,
@ -779,12 +814,12 @@ impl StackingContextLayerCreator {
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() {
state.add_stacking_context(child_stacking_context, stacking_context);
}
state.finish_building_current_layer(stacking_context);
stacking_context.last_child_layer_info =
StackingContextLayerCreator::find_last_child_layer_info(stacking_context);
}
#[inline]
@ -792,6 +827,97 @@ impl StackingContextLayerCreator {
self.next_layer_info.is_some()
}
#[inline]
fn layerize_display_list_section(&mut self,
section: DisplayListSection,
stacking_context: &mut StackingContext) {
let section_list = stacking_context.display_list.get_section_mut(section).split_off(0);
for item in section_list.into_iter() {
self.add_display_item(item, section, stacking_context);
}
}
#[inline]
fn display_item_needs_layer(&mut self, item: &DisplayItem) -> bool {
match *item {
LayeredItemClass(_) => true,
_ => self.all_following_children_need_layers(),
}
}
#[inline]
fn prepare_ordering_layer(&mut self,
stacking_context: &mut StackingContext) {
if self.building_ordering_layer {
assert!(self.next_layer_info.is_some());
return;
}
let next_layer_info = Some(stacking_context
.get_layer_info(self.next_layer_info.unwrap().layer_id)
.next_with_scroll_policy(ScrollPolicy::Scrollable));
self.finish_building_current_layer(stacking_context);
self.next_layer_info = next_layer_info;
self.building_ordering_layer = true;
}
fn add_display_item(&mut self,
item: DisplayItem,
section: DisplayListSection,
stacking_context: &mut StackingContext) {
if !self.display_item_needs_layer(&item) {
stacking_context.display_list.get_section_mut(section).push_back(item);
return;
}
if let LayeredItemClass(ref item) = item {
if let Some(ref next_layer_info) = self.next_layer_info {
if item.layer_id == next_layer_info.layer_id && !self.building_ordering_layer {
return;
}
}
self.finish_building_current_layer(stacking_context);
self.building_ordering_layer = false;
self.next_layer_info = Some(stacking_context.get_layer_info(item.layer_id).clone());
} else {
self.prepare_ordering_layer(stacking_context);
}
match item {
LayeredItemClass(layered_item) =>
self.add_display_item_to_display_list(layered_item.item, section),
_ => self.add_display_item_to_display_list(item, section),
}
}
fn add_display_item_to_display_list(&mut self,
item: DisplayItem,
section: DisplayListSection) {
if self.display_list_for_next_layer.is_none() {
self.display_list_for_next_layer = Some(DisplayList::new());
}
if let Some(ref mut display_list) = self.display_list_for_next_layer {
display_list.get_section_mut(section).push_back(item);
}
}
fn find_last_child_layer_info(stacking_context: &mut StackingContext) -> Option<LayerInfo> {
if let Some(layer) = stacking_context.display_list.layered_children.back() {
return Some(LayerInfo::new(layer.id, ScrollPolicy::Scrollable, None));
}
// We only care about the last child, because a layer in a child's hierarchy
// automatically gives following children a layer, so they will be in the
// 'layered_children' list instead of 'children'.
match stacking_context.display_list.children.back() {
Some(child) => child.last_child_layer_info,
None => None,
}
}
#[inline]
fn finish_building_current_layer(&mut self, stacking_context: &mut StackingContext) {
if let Some(display_list) = self.display_list_for_next_layer.take() {
@ -810,6 +936,15 @@ impl StackingContextLayerCreator {
return;
}
// This StackingContext has a layered child somewhere in its children.
// We need to give all new StackingContexts their own layer, so that they
// draw on top of this layered child.
if let Some(layer_info) = stacking_context.last_child_layer_info {
self.building_ordering_layer = true;
self.next_layer_info =
Some(layer_info.clone().next_with_scroll_policy(ScrollPolicy::Scrollable));
}
parent_stacking_context.display_list.children.push_back(stacking_context);
}
@ -822,8 +957,10 @@ impl StackingContextLayerCreator {
// 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.building_ordering_layer = 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,
@ -831,6 +968,8 @@ impl StackingContextLayerCreator {
return;
}
self.prepare_ordering_layer(parent_stacking_context);
if self.display_list_for_next_layer.is_none() {
self.display_list_for_next_layer = Some(DisplayList::new());
}
@ -850,6 +989,8 @@ pub enum DisplayItem {
GradientClass(Box<GradientDisplayItem>),
LineClass(Box<LineDisplayItem>),
BoxShadowClass(Box<BoxShadowDisplayItem>),
LayeredItemClass(Box<LayeredItem>),
NoopClass(Box<BaseDisplayItem>),
}
/// Information common to all display items.
@ -1254,6 +1395,16 @@ pub struct BoxShadowDisplayItem {
pub clip_mode: BoxShadowClipMode,
}
/// Contains an item that should get its own layer during layer creation.
#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
pub struct LayeredItem {
/// Fields common to all display items.
pub item: DisplayItem,
/// The id of the layer this item belongs to.
pub layer_id: LayerId,
}
/// How a box shadow should be clipped.
#[derive(Clone, Copy, Debug, PartialEq, HeapSizeOf, Deserialize, Serialize)]
pub enum BoxShadowClipMode {
@ -1337,8 +1488,12 @@ impl DisplayItem {
box_shadow.color,
box_shadow.blur_radius,
box_shadow.spread_radius,
box_shadow.clip_mode)
box_shadow.clip_mode);
}
DisplayItem::LayeredItemClass(_) => panic!("Found layered item during drawing."),
DisplayItem::NoopClass(_) => { }
}
}
@ -1351,6 +1506,8 @@ impl DisplayItem {
DisplayItem::GradientClass(ref gradient) => &gradient.base,
DisplayItem::LineClass(ref line) => &line.base,
DisplayItem::BoxShadowClass(ref box_shadow) => &box_shadow.base,
DisplayItem::LayeredItemClass(ref layered_item) => layered_item.item.base(),
DisplayItem::NoopClass(ref base_item) => base_item,
}
}
@ -1363,6 +1520,8 @@ impl DisplayItem {
DisplayItem::GradientClass(ref mut gradient) => &mut gradient.base,
DisplayItem::LineClass(ref mut line) => &mut line.base,
DisplayItem::BoxShadowClass(ref mut box_shadow) => &mut box_shadow.base,
DisplayItem::LayeredItemClass(ref mut layered_item) => layered_item.item.mut_base(),
DisplayItem::NoopClass(ref mut base_item) => base_item,
}
}
@ -1395,6 +1554,9 @@ impl fmt::Debug for DisplayItem {
DisplayItem::GradientClass(_) => "Gradient".to_owned(),
DisplayItem::LineClass(_) => "Line".to_owned(),
DisplayItem::BoxShadowClass(_) => "BoxShadow".to_owned(),
DisplayItem::LayeredItemClass(ref layered_item) =>
format!("LayeredItem({:?})", layered_item.item),
DisplayItem::NoopClass(_) => "Noop".to_owned(),
},
self.base().bounds,
self.base().metadata.node.id()

View file

@ -19,11 +19,10 @@ use gfx_traits::color;
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, SubpageLayerInfo};
use msg::compositor_msg::{Epoch, FrameTreeId, LayerId, LayerKind, LayerProperties};
use msg::compositor_msg::{PaintListener, ScrollPolicy};
use msg::constellation_msg::Msg as ConstellationMsg;
use msg::constellation_msg::PipelineExitType;
use msg::constellation_msg::{ConstellationChan, Failure, PipelineId};
use msg::constellation_msg::{ConstellationChan, Failure, PipelineExitType, PipelineId};
use paint_context::PaintContext;
use profile_traits::mem::{self, ReportsChan};
use profile_traits::time::{self, profile};
@ -60,8 +59,8 @@ pub struct PaintLayer {
pub bounds: Rect<Au>,
/// 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>,
/// The pipeline of the subpage that this layer represents, if there is one.
pub subpage_pipeline_id: Option<PipelineId>,
}
impl PaintLayer {
@ -78,7 +77,7 @@ impl PaintLayer {
contents: PaintLayerContents::StackingContext(stacking_context),
bounds: bounds,
scroll_policy: layer_info.scroll_policy,
subpage_layer_info: layer_info.subpage_layer_info,
subpage_pipeline_id: layer_info.subpage_pipeline_id,
}
}
@ -93,7 +92,7 @@ impl PaintLayer {
contents: PaintLayerContents::DisplayList(Arc::new(display_list)),
bounds: bounds,
scroll_policy: layer_info.scroll_policy,
subpage_layer_info: layer_info.subpage_layer_info,
subpage_pipeline_id: layer_info.subpage_pipeline_id,
}
}
@ -149,7 +148,7 @@ impl PaintLayer {
perspective: perspective,
establishes_3d_context: establishes_3d_context,
scrolls_overflow_area: scrolls_overflow_area,
subpage_layer_info: self.subpage_layer_info,
subpage_pipeline_id: self.subpage_pipeline_id,
}
}