diff options
author | bors-servo <metajack+bors@gmail.com> | 2015-10-20 16:01:38 -0600 |
---|---|---|
committer | bors-servo <metajack+bors@gmail.com> | 2015-10-20 16:01:38 -0600 |
commit | 11d23a41b31c2b2846d1e9c6b40e87ba7e2a095f (patch) | |
tree | b4476c6acf563aaf5b980ec9694fc9b1c7d98cf2 | |
parent | c3ab71109ee2ffcc31b40890f4c6739d8f5b1333 (diff) | |
parent | ac5525aeeb3df60a99b503fa75f919c93c50b43b (diff) | |
download | servo-11d23a41b31c2b2846d1e9c6b40e87ba7e2a095f.tar.gz servo-11d23a41b31c2b2846d1e9c6b40e87ba7e2a095f.zip |
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 -->
-rw-r--r-- | components/compositing/compositor.rs | 20 | ||||
-rw-r--r-- | components/compositing/compositor_layer.rs | 8 | ||||
-rw-r--r-- | components/gfx/display_list/mod.rs | 212 | ||||
-rw-r--r-- | components/gfx/paint_task.rs | 17 | ||||
-rw-r--r-- | components/layout/display_list_builder.rs | 52 | ||||
-rw-r--r-- | components/layout/fragment.rs | 6 | ||||
-rw-r--r-- | components/layout/inline.rs | 2 | ||||
-rw-r--r-- | components/msg/compositor_msg.rs | 13 | ||||
-rw-r--r-- | components/servo/Cargo.lock | 2 | ||||
-rw-r--r-- | ports/cef/Cargo.lock | 2 | ||||
-rw-r--r-- | ports/gonk/Cargo.lock | 2 | ||||
-rw-r--r-- | tests/wpt/mozilla/tests/css/stacked_layers.html | 16 | ||||
-rw-r--r-- | tests/wpt/mozilla/tests/css/stacked_layers_ref.html | 10 |
13 files changed, 271 insertions, 91 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index dc7d54cfa5e..739cc1ddb44 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -670,7 +670,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { scroll_policy: ScrollPolicy::Scrollable, transform: Matrix4::identity(), perspective: Matrix4::identity(), - subpage_layer_info: None, + subpage_pipeline_id: None, establishes_3d_context: true, scrolls_overflow_area: false, }; @@ -819,18 +819,16 @@ impl<Window: WindowMethods> IOCompositor<Window> { } // If this layer contains a subpage, then create the root layer for that subpage now. - if let Some(ref subpage_layer_info) = layer_properties.subpage_layer_info { + if let Some(ref subpage_pipeline_id) = layer_properties.subpage_pipeline_id { let subpage_layer_properties = LayerProperties { id: LayerId::null(), parent_id: None, - rect: Rect::new(Point2D::new(subpage_layer_info.origin.x.to_f32_px(), - subpage_layer_info.origin.y.to_f32_px()), - layer_properties.rect.size), + rect: Rect::new(Point2D::zero(), layer_properties.rect.size), background_color: layer_properties.background_color, scroll_policy: ScrollPolicy::Scrollable, transform: Matrix4::identity(), perspective: Matrix4::identity(), - subpage_layer_info: layer_properties.subpage_layer_info, + subpage_pipeline_id: layer_properties.subpage_pipeline_id, establishes_3d_context: true, scrolls_overflow_area: true, }; @@ -840,13 +838,13 @@ impl<Window: WindowMethods> IOCompositor<Window> { } else { WantsScrollEventsFlag::DoesntWantScrollEvents }; - let subpage_layer = CompositorData::new_layer(subpage_layer_info.pipeline_id, + let subpage_layer = CompositorData::new_layer(*subpage_pipeline_id, subpage_layer_properties, wants_scroll_events, new_layer.tile_size); *subpage_layer.masks_to_bounds.borrow_mut() = true; new_layer.add_child(subpage_layer); - self.pending_subpages.insert(subpage_layer_info.pipeline_id); + self.pending_subpages.insert(*subpage_pipeline_id); } parent_layer.add_child(new_layer.clone()); @@ -871,13 +869,13 @@ impl<Window: WindowMethods> IOCompositor<Window> { /// Sends the size of the given subpage up to the constellation. This will often trigger a /// reflow of that subpage. fn update_subpage_size_if_necessary(&self, layer_properties: &LayerProperties) { - let subpage_layer_info = match layer_properties.subpage_layer_info { - Some(ref subpage_layer_info) => *subpage_layer_info, + let subpage_pipeline_id = match layer_properties.subpage_pipeline_id { + Some(ref subpage_pipeline_id) => subpage_pipeline_id, None => return, }; let ConstellationChan(ref chan) = self.constellation_chan; - chan.send(ConstellationMsg::FrameSize(subpage_layer_info.pipeline_id, + chan.send(ConstellationMsg::FrameSize(*subpage_pipeline_id, layer_properties.rect.size)).unwrap(); } diff --git a/components/compositing/compositor_layer.rs b/components/compositing/compositor_layer.rs index 525135fd208..e3661987a78 100644 --- a/components/compositing/compositor_layer.rs +++ b/components/compositing/compositor_layer.rs @@ -61,9 +61,7 @@ impl CompositorData { requested_epoch: Epoch(0), painted_epoch: Epoch(0), scroll_offset: Point2D::typed(0., 0.), - subpage_info: layer_properties.subpage_layer_info.map(|subpage_layer_info| { - subpage_layer_info.pipeline_id - }), + subpage_info: layer_properties.subpage_pipeline_id, }; Rc::new(Layer::new(Rect::from_untyped(&layer_properties.rect), @@ -485,8 +483,8 @@ impl RcCompositorLayer for Rc<Layer<CompositorData>> { if let Some(layer_pipeline_id) = layer_pipeline_id { for layer_properties in new_layers.iter() { // Keep this layer if a reference to it exists. - if let Some(ref subpage_layer_info) = layer_properties.subpage_layer_info { - if subpage_layer_info.pipeline_id == layer_pipeline_id { + if let Some(ref subpage_pipeline_id) = layer_properties.subpage_pipeline_id { + if *subpage_pipeline_id == layer_pipeline_id { return true } } diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index 07f32519ab9..5fb8b99d990 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -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] @@ -793,6 +828,97 @@ impl StackingContextLayerCreator { } #[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() { let layer_info = self.next_layer_info.take().unwrap(); @@ -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() diff --git a/components/gfx/paint_task.rs b/components/gfx/paint_task.rs index 0c58155ab2d..e33432caf57 100644 --- a/components/gfx/paint_task.rs +++ b/components/gfx/paint_task.rs @@ -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, } } diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 299f0155e4d..37a3a543794 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -15,6 +15,7 @@ use azure::azure_hl::Color; use block::BlockFlow; use canvas_traits::{CanvasMsg, FromLayoutMsg}; use context::LayoutContext; +use euclid::num::Zero; use euclid::{Matrix4, Point2D, Point3D, Rect, SideOffsets2D, Size2D}; use flex::FlexFlow; use flow::{self, BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED}; @@ -25,8 +26,8 @@ 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, LayerInfo, LineDisplayItem}; -use gfx::display_list::{OpaqueNode, SolidColorDisplayItem}; +use gfx::display_list::{GradientStop, ImageDisplayItem, LayeredItem, LayerInfo}; +use gfx::display_list::{LineDisplayItem, OpaqueNode, SolidColorDisplayItem}; use gfx::display_list::{StackingContext, TextDisplayItem, TextOrientation}; use gfx::paint_task::THREAD_TINT_COLORS; use gfx::text::glyph::CharIndex; @@ -35,7 +36,7 @@ use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT}; use ipc_channel::ipc::{self, IpcSharedMemory}; use list_item::ListItemFlow; use model::{self, MaybeAuto, ToGfxMatrix}; -use msg::compositor_msg::{ScrollPolicy, SubpageLayerInfo}; +use msg::compositor_msg::ScrollPolicy; use net_traits::image::base::{Image, PixelFormat}; use net_traits::image_cache_task::UsePlaceholder; use std::default::Default; @@ -1098,7 +1099,6 @@ impl FragmentDisplayListBuilding for Fragment { } SpecificFragmentInfo::Generic | SpecificFragmentInfo::GeneratedContent(..) | - SpecificFragmentInfo::Iframe(..) | SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell | SpecificFragmentInfo::TableRow | @@ -1112,6 +1112,27 @@ impl FragmentDisplayListBuilding for Fragment { clip); } } + SpecificFragmentInfo::Iframe(ref fragment_info) => { + // TODO(mrobinson): When https://github.com/servo/euclid/issues/109 is fixed this + // check can just become stacking_relative_content_box.is_empty(). + if stacking_relative_content_box.size.width != Zero::zero() && + stacking_relative_content_box.size.height != Zero::zero() { + let layer_id = self.layer_id(); + display_list.content.push_back(DisplayItem::LayeredItemClass(box LayeredItem { + item: DisplayItem::NoopClass( + box BaseDisplayItem::new(stacking_relative_content_box, + DisplayItemMetadata::new(self.node, + &*self.style, + Cursor::DefaultCursor), + (*clip).clone())), + layer_id: layer_id + })); + + display_list.layer_info.push_back(LayerInfo::new(layer_id, + ScrollPolicy::Scrollable, + Some(fragment_info.pipeline_id))); + } + } SpecificFragmentInfo::Image(ref mut image_fragment) => { // Place the image into the display list. if let Some(ref image) = image_fragment.image { @@ -1284,19 +1305,8 @@ impl FragmentDisplayListBuilding for Fragment { filters.push(Filter::Opacity(effects.opacity)) } - 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); - Some(SubpageLayerInfo { - pipeline_id: iframe_fragment_info.pipeline_id, - origin: Point2D::new(border_padding.left, border_padding.top), - }) - } - _ => None, - }; - - let canvas_or_iframe = match self.specific { - SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Iframe(_) => true, + let canvas = match self.specific { + SpecificFragmentInfo::Canvas(_) => true, _ => false }; @@ -1304,11 +1314,9 @@ impl FragmentDisplayListBuilding for Fragment { // 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)) + Some(LayerInfo::new(self.layer_id_for_overflow_scroll(), scroll_policy, None)) + } else if self.flags.contains(HAS_LAYER) || canvas { + Some(LayerInfo::new(self.layer_id(), scroll_policy, None)) } else { None }; diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 308532d9768..3623e1c5d76 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -2107,11 +2107,11 @@ impl Fragment { } /// Returns true if this fragment unconditionally layerizes. - pub fn needs_layer(&self) -> bool { + pub fn needs_layered_stacking_context(&self) -> bool { // Canvas and iframes always layerize, as an special case // FIXME(pcwalton): Don't unconditionally form stacking contexts for each canvas. match self.specific { - SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Iframe(_) => true, + SpecificFragmentInfo::Canvas(_) => true, _ => false, } } @@ -2140,7 +2140,7 @@ impl Fragment { transform_style::T::auto => {} } - if self.needs_layer() { + if self.needs_layered_stacking_context() { return true } diff --git a/components/layout/inline.rs b/components/layout/inline.rs index d6704405e1b..dbe61662b12 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -1496,7 +1496,7 @@ impl Flow for InlineFlow { for fragment_index in line.range.each_index() { let fragment = &mut self.fragments.fragments[fragment_index.to_usize()]; - if fragment.needs_layer() && !fragment.is_positioned() { + if fragment.needs_layered_stacking_context() && !fragment.is_positioned() { layers_needed_for_descendants = true } diff --git a/components/msg/compositor_msg.rs b/components/msg/compositor_msg.rs index 8c411148c9a..e7612351724 100644 --- a/components/msg/compositor_msg.rs +++ b/components/msg/compositor_msg.rs @@ -2,7 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use app_units::Au; use azure::azure_hl::Color; use constellation_msg::{Key, KeyModifiers, KeyState, PipelineId}; use euclid::{Matrix4, Point2D, Rect, Size2D}; @@ -120,7 +119,7 @@ pub struct LayerProperties { pub perspective: Matrix4, /// The subpage that this layer represents. If this is `Some`, this layer represents an /// iframe. - pub subpage_layer_info: Option<SubpageLayerInfo>, + pub subpage_pipeline_id: Option<PipelineId>, /// Whether this layer establishes a new 3d rendering context. pub establishes_3d_context: bool, /// Whether this layer scrolls its overflow area. @@ -163,13 +162,3 @@ pub enum ScriptToCompositorMsg { ResizeTo(Size2D<u32>), Exit, } - -/// Subpage (i.e. iframe)-specific information about each layer. -#[derive(Clone, Copy, Debug, Deserialize, Serialize, HeapSizeOf)] -pub struct SubpageLayerInfo { - /// The ID of the pipeline. - pub pipeline_id: PipelineId, - /// The offset of the subpage within this layer (to account for borders). - pub origin: Point2D<Au>, -} - diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 20c56d42776..81b62bf7a1f 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -978,7 +978,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "layers" version = "0.1.0" -source = "git+https://github.com/servo/rust-layers#497a54e403ff737c35e47b29c664ed8ae8ee26cf" +source = "git+https://github.com/servo/rust-layers#5af8c6bb9801e4f8d337c6a74a0bb2641ab48e0e" dependencies = [ "azure 0.1.0 (git+https://github.com/servo/rust-azure)", "cgl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index b92931c5a7c..04a658e73fe 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -928,7 +928,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "layers" version = "0.1.0" -source = "git+https://github.com/servo/rust-layers#497a54e403ff737c35e47b29c664ed8ae8ee26cf" +source = "git+https://github.com/servo/rust-layers#5af8c6bb9801e4f8d337c6a74a0bb2641ab48e0e" dependencies = [ "azure 0.1.0 (git+https://github.com/servo/rust-azure)", "cgl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ports/gonk/Cargo.lock b/ports/gonk/Cargo.lock index c5b2291d0d8..ef5b60b87ad 100644 --- a/ports/gonk/Cargo.lock +++ b/ports/gonk/Cargo.lock @@ -808,7 +808,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "layers" version = "0.1.0" -source = "git+https://github.com/servo/rust-layers#497a54e403ff737c35e47b29c664ed8ae8ee26cf" +source = "git+https://github.com/servo/rust-layers#5af8c6bb9801e4f8d337c6a74a0bb2641ab48e0e" dependencies = [ "azure 0.1.0 (git+https://github.com/servo/rust-azure)", "cgl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/tests/wpt/mozilla/tests/css/stacked_layers.html b/tests/wpt/mozilla/tests/css/stacked_layers.html index a0edbaf667c..d135ab144cd 100644 --- a/tests/wpt/mozilla/tests/css/stacked_layers.html +++ b/tests/wpt/mozilla/tests/css/stacked_layers.html @@ -8,6 +8,7 @@ .gray { background: rgb(200, 200, 200); } .grayer { background: rgb(80, 80, 80); } .grayest { background: rgb(0, 0, 0); } + iframe { display: block; border: 0; } </style> </head> <body> @@ -27,5 +28,20 @@ <div class="grayer box" style="margin-left: 10px; margin-top: 10px; opacity: 0.999; z-index: -1;"></div> <div class="gray box" style="margin-left: 20px; margin-top: -40px; opacity: 0.999;"> </div> </div> + + <!-- The iframe should be painted in tree order since it is not positioned and + the following div is. --> + <div class="test grayest box"> + <iframe class="box" style="margin-left: 10px; margin-top: 10px;" src="data:text/html;charset=utf-8;base64,PGh0bWw+PGJvZHkgc3R5bGU9ImJhY2tncm91bmQ6IHJnYig4MCwgODAsIDgwKTsiPjwvYm9keT48L2Rpdj4="></iframe> + <div class="gray box" style="position: relative; left: 20px; top: -40px;"> </div> + </div> + + <!-- The iframe should be painted in tree order since both it and the inner div are + not positioned elements. --> + <div class="test grayest box"> + <iframe class="box" style="position: relative; left: 10px; top: 10px;" src="data:text/html;charset=utf-8;base64,PGh0bWw+PGJvZHkgc3R5bGU9ImJhY2tncm91bmQ6IHJnYig4MCwgODAsIDgwKTsiPjwvYm9keT48L2Rpdj4="></iframe> + <div class="gray box" style="position: relative; left: 20px; top: -30px;"> </div> + </div> + </body> </html> diff --git a/tests/wpt/mozilla/tests/css/stacked_layers_ref.html b/tests/wpt/mozilla/tests/css/stacked_layers_ref.html index fbec3c30c7d..a166e23cae7 100644 --- a/tests/wpt/mozilla/tests/css/stacked_layers_ref.html +++ b/tests/wpt/mozilla/tests/css/stacked_layers_ref.html @@ -24,5 +24,15 @@ <div class="grayer box" style="margin-left: 10px; margin-top: 10px; position: absolute; opacity: 0.999;"></div> <div class="gray box" style="margin-left: 20px; margin-top: 20px; position: relative; opacity: 0.999;"></div> </div> + + <div class="test grayest box"> + <div class="grayer box" style="margin-left: 10px; margin-top: 10px;"></div> + <div class="gray box" style="margin-left: 20px; margin-top: -40px;"></div> + </div> + + <div class="test grayest box"> + <div class="grayer box" style="margin-left: 10px; margin-top: 10px;"></div> + <div class="gray box" style="margin-left: 20px; margin-top: -40px;"></div> + </div> </body> </html> |