aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2015-10-13 17:29:29 -0700
committerMartin Robinson <mrobinson@igalia.com>2015-11-03 17:47:39 -0800
commitc1a38e240afdfaed0f223f2a4e205d05554f322e (patch)
tree80046e0c11b1ca3b3070391794cfc4da4fca6420
parent5c11c88e92ccbc3013501096d5625778774c9fee (diff)
downloadservo-c1a38e240afdfaed0f223f2a4e205d05554f322e.tar.gz
servo-c1a38e240afdfaed0f223f2a4e205d05554f322e.zip
Mix stacking contexts into the positioned content list
Sometimes positioned content needs to be layered on top of stacking contexts. The layer synthesis code can do this, but the current design prevents it because stacking contexts are stored in a separate struct member. In order to preserve tree order, mix stacking contexts into the positioned content list, by adding a new StackingContextClass DisplayItem. Such items do not have a base DisplayItem. In some ways this simplifies the code, because we no longer have to have a separate code path in the StackingContextLayerCreator. Fixes #7779. Fixes #7983. Fixes #8122. Fixes #8310.
-rw-r--r--components/gfx/display_list/mod.rs464
-rw-r--r--components/gfx/display_list/optimizer.rs63
-rw-r--r--components/gfx/paint_task.rs19
-rw-r--r--components/layout/display_list_builder.rs14
-rw-r--r--components/layout/flow.rs18
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/floats-154.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/left-offset-position-fixed-001.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/max-height-107.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/max-height-110.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/min-height-104.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/min-height-105.htm.ini3
-rw-r--r--tests/wpt/mozilla/tests/css/stacked_layers.html17
-rw-r--r--tests/wpt/mozilla/tests/css/stacked_layers_ref.html10
13 files changed, 329 insertions, 294 deletions
diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs
index 5fb8b99d990..d69353e1f72 100644
--- a/components/gfx/display_list/mod.rs
+++ b/components/gfx/display_list/mod.rs
@@ -31,6 +31,7 @@ use paint_task::{PaintLayerContents, PaintLayer};
use self::DisplayItem::*;
use self::DisplayItemIterator::*;
use smallvec::SmallVec;
+use std::cmp::Ordering;
use std::collections::linked_list::{self, LinkedList};
use std::fmt;
use std::mem;
@@ -141,8 +142,6 @@ pub struct DisplayList {
pub positioned_content: LinkedList<DisplayItem>,
/// Outlines: step 10.
pub outlines: LinkedList<DisplayItem>,
- /// Child stacking contexts.
- 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.
@@ -160,7 +159,6 @@ impl DisplayList {
content: LinkedList::new(),
positioned_content: LinkedList::new(),
outlines: LinkedList::new(),
- children: LinkedList::new(),
layered_children: LinkedList::new(),
layer_info: LinkedList::new(),
}
@@ -176,16 +174,16 @@ impl DisplayList {
self.content.append(&mut other.content);
self.positioned_content.append(&mut other.positioned_content);
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.
+ /// From E.2.5 at http://www.w3.org/TR/CSS21/zindex.html. We do not include positioned content
+ /// and stacking contexts in the pseudo-stacking-context.
#[inline]
pub fn form_float_pseudo_stacking_context(&mut self) {
prepend_from(&mut self.floats, &mut self.outlines);
- prepend_from(&mut self.floats, &mut self.positioned_content);
prepend_from(&mut self.floats, &mut self.content);
prepend_from(&mut self.floats, &mut self.block_backgrounds_and_borders);
prepend_from(&mut self.floats, &mut self.background_and_borders);
@@ -204,25 +202,33 @@ impl DisplayList {
/// Returns a list of all items in this display list concatenated together. This is extremely
/// inefficient and should only be used for debugging.
- pub fn all_display_items(&self) -> Vec<DisplayItem> {
+ pub fn flatten(&self) -> Vec<DisplayItem> {
let mut result = Vec::new();
+ fn flatten_item(result: &mut Vec<DisplayItem>, item: &DisplayItem) {
+ match item {
+ &DisplayItem::StackingContextClass(ref stacking_context) =>
+ result.extend(stacking_context.display_list.flatten().into_iter()),
+ _ => result.push((*item).clone()),
+ }
+ }
+
for display_item in &self.background_and_borders {
- result.push((*display_item).clone())
+ flatten_item(&mut result, display_item);
}
for display_item in &self.block_backgrounds_and_borders {
- result.push((*display_item).clone())
+ flatten_item(&mut result, display_item);
}
for display_item in &self.floats {
- result.push((*display_item).clone())
+ flatten_item(&mut result, display_item);
}
for display_item in &self.content {
- result.push((*display_item).clone())
+ flatten_item(&mut result, display_item);
}
for display_item in &self.positioned_content {
- result.push((*display_item).clone())
+ flatten_item(&mut result, display_item);
}
for display_item in &self.outlines {
- result.push((*display_item).clone())
+ flatten_item(&mut result, display_item);
}
result
}
@@ -242,7 +248,11 @@ impl DisplayList {
print_tree.new_level(title.to_owned());
for item in items {
- print_tree.add_item(format!("{:?}", item));
+ match item {
+ &DisplayItem::StackingContextClass(ref stacking_context) =>
+ stacking_context.print_with_tree(print_tree),
+ _ => print_tree.add_item(format!("{:?}", item)),
+ }
}
print_tree.end_level();
}
@@ -258,15 +268,6 @@ impl DisplayList {
print_display_list_section(print_tree, &self.positioned_content, "Positioned Content");
print_display_list_section(print_tree, &self.outlines, "Outlines");
-
- if !self.children.is_empty() {
- print_tree.new_level("Stacking Contexts".to_owned());
- for stacking_context in &self.children {
- stacking_context.print_with_tree(print_tree);
- }
- print_tree.end_level();
- }
-
if !self.layered_children.is_empty() {
print_tree.new_level("Layers".to_owned());
for paint_layer in &self.layered_children {
@@ -301,8 +302,6 @@ impl DisplayList {
layer_kind: paint_context.layer_kind,
};
- let pixels_per_px = paint_subcontext.screen_pixels_per_px();
-
if opts::get().dump_display_list_optimized {
self.print(format!("Optimized display list. Tile bounds: {:?}",
paint_context.page_rect));
@@ -318,74 +317,48 @@ impl DisplayList {
// Steps 1 and 2: Borders and background for the root.
for display_item in &self.background_and_borders {
- display_item.draw_into_context(&mut paint_subcontext)
+ display_item.draw_into_context(transform, &mut paint_subcontext)
}
// Step 3: Positioned descendants with negative z-indices.
- for positioned_kid in &self.children {
- if positioned_kid.z_index >= 0 {
- break
+ for positioned_kid in &self.positioned_content {
+ if let &DisplayItem::StackingContextClass(ref stacking_context) = positioned_kid {
+ if stacking_context.z_index < 0 {
+ positioned_kid.draw_into_context(transform, &mut paint_subcontext);
+ }
}
- let new_transform =
- transform.translate(positioned_kid.bounds
- .origin
- .x
- .to_nearest_pixel(pixels_per_px) as AzFloat,
- positioned_kid.bounds
- .origin
- .y
- .to_nearest_pixel(pixels_per_px) as AzFloat,
- 0.0);
- positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext,
- &new_transform,
- Some(&positioned_kid.overflow))
}
// Step 4: Block backgrounds and borders.
for display_item in &self.block_backgrounds_and_borders {
- display_item.draw_into_context(&mut paint_subcontext)
+ display_item.draw_into_context(transform, &mut paint_subcontext)
}
// Step 5: Floats.
for display_item in &self.floats {
- display_item.draw_into_context(&mut paint_subcontext)
+ display_item.draw_into_context(transform, &mut paint_subcontext)
}
// TODO(pcwalton): Step 6: Inlines that generate stacking contexts.
// Step 7: Content.
for display_item in &self.content {
- display_item.draw_into_context(&mut paint_subcontext)
- }
-
- // Step 8: Positioned descendants with `z-index: auto`.
- for display_item in &self.positioned_content {
- display_item.draw_into_context(&mut paint_subcontext)
+ display_item.draw_into_context(transform, &mut paint_subcontext)
}
- // Step 9: Positioned descendants with nonnegative, numeric z-indices.
- for positioned_kid in &self.children {
- if positioned_kid.z_index < 0 {
- continue
+ // Step 8 & 9: Positioned descendants with nonnegative, numeric z-indices.
+ for positioned_kid in &self.positioned_content {
+ if let &DisplayItem::StackingContextClass(ref stacking_context) = positioned_kid {
+ if stacking_context.z_index < 0 {
+ continue;
+ }
}
- let new_transform =
- transform.translate(positioned_kid.bounds
- .origin
- .x
- .to_nearest_pixel(pixels_per_px) as AzFloat,
- positioned_kid.bounds
- .origin
- .y
- .to_nearest_pixel(pixels_per_px) as AzFloat,
- 0.0);
- positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext,
- &new_transform,
- Some(&positioned_kid.overflow))
+ positioned_kid.draw_into_context(transform, &mut paint_subcontext);
}
// Step 10: Outlines.
for display_item in &self.outlines {
- display_item.draw_into_context(&mut paint_subcontext)
+ display_item.draw_into_context(transform, &mut paint_subcontext)
}
// Undo our clipping and transform.
@@ -398,25 +371,27 @@ impl DisplayList {
point: Point2D<Au>,
result: &mut Vec<DisplayItemMetadata>,
topmost_only: bool) {
- fn hit_test_in_list<'a, I>(point: Point2D<Au>,
- result: &mut Vec<DisplayItemMetadata>,
- topmost_only: bool,
- iterator: I)
- where I: Iterator<Item=&'a DisplayItem> {
- for item in iterator {
+ fn hit_test_item(point: Point2D<Au>,
+ result: &mut Vec<DisplayItemMetadata>,
+ item: &DisplayItem) {
+ let base_item = match item.base() {
+ Some(base) => base,
+ None => return,
+ };
+
// TODO(pcwalton): Use a precise algorithm here. This will allow us to properly hit
// test elements with `border-radius`, for example.
- if !item.base().clip.might_intersect_point(&point) {
+ if !base_item.clip.might_intersect_point(&point) {
// Clipped out.
- continue
+ return;
}
if !geometry::rect_contains_point(item.bounds(), point) {
// Can't possibly hit.
- continue
+ return;
}
- if item.base().metadata.pointing.is_none() {
+ if base_item.metadata.pointing.is_none() {
// `pointer-events` is `none`. Ignore this item.
- continue
+ return;
}
if let DisplayItem::BorderClass(ref border) = *item {
@@ -434,14 +409,23 @@ impl DisplayList {
(border.border_widths.top +
border.border_widths.bottom)));
if geometry::rect_contains_point(interior_rect, point) {
- continue
+ return;
}
}
// We found a hit!
- result.push(item.base().metadata);
- if topmost_only {
- return
+ result.push(base_item.metadata);
+ }
+
+ fn hit_test_in_list<'a, I>(point: Point2D<Au>,
+ result: &mut Vec<DisplayItemMetadata>,
+ topmost_only: bool,
+ iterator: I)
+ where I: Iterator<Item=&'a DisplayItem> {
+ for item in iterator {
+ hit_test_item(point, result, item);
+ if topmost_only && !result.is_empty() {
+ return;
}
}
}
@@ -470,11 +454,16 @@ impl DisplayList {
}
// Steps 9 and 8: Positioned descendants with nonnegative z-indices.
- for kid in self.children.iter().rev() {
- if kid.z_index < 0 {
- continue
+ for kid in self.positioned_content.iter().rev() {
+ if let &DisplayItem::StackingContextClass(ref stacking_context) = kid {
+ if stacking_context.z_index < 0 {
+ continue
+ }
+ stacking_context.hit_test(point, result, topmost_only);
+ } else {
+ hit_test_item(point, result, kid);
}
- kid.hit_test(point, result, topmost_only);
+
if topmost_only && !result.is_empty() {
return
}
@@ -485,7 +474,6 @@ impl DisplayList {
//
// TODO(pcwalton): Step 6: Inlines that generate stacking contexts.
for display_list in &[
- &self.positioned_content,
&self.content,
&self.floats,
&self.block_backgrounds_and_borders,
@@ -496,14 +484,15 @@ impl DisplayList {
}
}
- // Step 3: Positioned descendants with negative z-indices.
- for kid in self.children.iter().rev() {
- if kid.z_index >= 0 {
- continue
- }
- kid.hit_test(point, result, topmost_only);
- if topmost_only && !result.is_empty() {
- return
+ for kid in self.positioned_content.iter().rev() {
+ if let &DisplayItem::StackingContextClass(ref stacking_context) = kid {
+ if stacking_context.z_index >= 0 {
+ continue
+ }
+ stacking_context.hit_test(point, result, topmost_only);
+ if topmost_only && !result.is_empty() {
+ return
+ }
}
}
@@ -523,9 +512,12 @@ impl DisplayList {
}
}
- for kid in &self.children {
- if let Some(paint_layer) = kid.display_list.find_layer_with_layer_id(layer_id) {
- return Some(paint_layer);
+ for item in &self.positioned_content {
+ if let &DisplayItem::StackingContextClass(ref stacking_context) = item {
+ if let Some(paint_layer)
+ = stacking_context.display_list.find_layer_with_layer_id(layer_id) {
+ return Some(paint_layer);
+ }
}
}
@@ -538,7 +530,7 @@ impl DisplayList {
pub fn calculate_bounding_rect(&self) -> Rect<Au> {
fn union_all_items(list: &LinkedList<DisplayItem>, mut bounds: Rect<Au>) -> Rect<Au> {
for item in list {
- bounds = bounds.union(&item.base().bounds);
+ bounds = bounds.union(&item.bounds());
}
bounds
};
@@ -550,13 +542,6 @@ impl DisplayList {
bounds = union_all_items(&self.content, bounds);
bounds = union_all_items(&self.positioned_content, bounds);
bounds = union_all_items(&self.outlines, bounds);
-
- for stacking_context in &self.children {
- bounds = bounds.union(&Rect::new(
- stacking_context.overflow.origin + stacking_context.bounds.origin,
- stacking_context.overflow.size));
- }
-
bounds
}
@@ -782,6 +767,7 @@ struct StackingContextLayerCreator {
display_list_for_next_layer: Option<DisplayList>,
next_layer_info: Option<LayerInfo>,
building_ordering_layer: bool,
+ last_child_layer_info: Option<LayerInfo>,
}
impl StackingContextLayerCreator {
@@ -790,6 +776,7 @@ impl StackingContextLayerCreator {
display_list_for_next_layer: None,
next_layer_info: None,
building_ordering_layer: false,
+ last_child_layer_info: None,
}
}
@@ -797,34 +784,43 @@ impl StackingContextLayerCreator {
fn add_layers_to_preserve_drawing_order(stacking_context: &mut StackingContext) {
let mut state = StackingContextLayerCreator::new();
+ // First we need to sort positioned content by z-index, so we can paint
+ // it in order and also so that we can detect situations where unlayered
+ // content should be on top of layered content.
+ let positioned_content = mem::replace(&mut stacking_context.display_list.positioned_content,
+ LinkedList::new());
+ let mut sorted_positioned_content: SmallVec<[DisplayItem; 8]> = SmallVec::new();
+ sorted_positioned_content.extend(positioned_content.into_iter());
+ sorted_positioned_content.sort_by(|this, other| this.compare_zindex(other));
+
+ // It's important here that we process all elements in paint order, so we can detect
+ // situations where layers are needed to maintain paint order.
state.layerize_display_list_section(DisplayListSection::BackgroundAndBorders,
stacking_context);
+
+ let mut remaining_positioned_content: SmallVec<[DisplayItem; 8]> = SmallVec::new();
+ for item in sorted_positioned_content.into_iter() {
+ if !item.has_negative_z_index() {
+ remaining_positioned_content.push(item);
+ } else {
+ state.add_display_item(item, DisplayListSection::PositionedContent, 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,
- 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));
-
- for child_stacking_context in sorted_children.into_iter() {
- state.add_stacking_context(child_stacking_context, stacking_context);
+ for item in remaining_positioned_content.into_iter() {
+ assert!(!item.has_negative_z_index());
+ state.add_display_item(item, DisplayListSection::PositionedContent, stacking_context);
}
- state.finish_building_current_layer(stacking_context);
- stacking_context.last_child_layer_info =
- StackingContextLayerCreator::find_last_child_layer_info(stacking_context);
- }
- #[inline]
- fn all_following_children_need_layers(&self) -> bool {
- self.next_layer_info.is_some()
+ state.layerize_display_list_section(DisplayListSection::Outlines, stacking_context);
+
+ state.finish_building_current_layer(stacking_context);
+ stacking_context.last_child_layer_info = state.find_last_child_layer_info(stacking_context);
}
#[inline]
@@ -838,9 +834,16 @@ impl StackingContextLayerCreator {
}
#[inline]
+ fn all_following_children_need_layers(&self) -> bool {
+ self.next_layer_info.is_some()
+ }
+
+ #[inline]
fn display_item_needs_layer(&mut self, item: &DisplayItem) -> bool {
match *item {
LayeredItemClass(_) => true,
+ StackingContextClass(ref stacking_context) =>
+ stacking_context.layer_info.is_some() || self.all_following_children_need_layers(),
_ => self.all_following_children_need_layers(),
}
}
@@ -865,31 +868,64 @@ impl StackingContextLayerCreator {
fn add_display_item(&mut self,
item: DisplayItem,
section: DisplayListSection,
- stacking_context: &mut StackingContext) {
+ parent_stacking_context: &mut StackingContext) {
if !self.display_item_needs_layer(&item) {
- stacking_context.display_list.get_section_mut(section).push_back(item);
+ if let DisplayItem::StackingContextClass(ref stacking_context) = item {
+ // 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.last_child_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.get_section_mut(section).push_back(item);
return;
}
- if let LayeredItemClass(ref item) = item {
+ if let StackingContextClass(ref stacking_context) = item {
+ // There is a bit of subtlety here. If this item is a stacking context,
+ // yet doesn't have a layer assigned this code will fall through. This means that
+ // stacking contexts that are promoted to layers will share layers with sibling
+ // display items.
+ let layer_info = stacking_context.layer_info.clone();
+ if let Some(mut layer_info) = layer_info {
+ self.finish_building_current_layer(parent_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.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.clone(),
+ color::transparent())));
+ return;
+ }
+ }
+
+ if let LayeredItemClass(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.finish_building_current_layer(parent_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);
+ self.next_layer_info =
+ Some(parent_stacking_context.get_layer_info(item.layer_id).clone());
+ self.add_display_item_to_display_list(item.item, section);
+ return;
}
- 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),
- }
+ self.prepare_ordering_layer(parent_stacking_context);
+ self.add_display_item_to_display_list(item, section);
}
fn add_display_item_to_display_list(&mut self,
@@ -904,18 +940,14 @@ impl StackingContextLayerCreator {
}
}
- fn find_last_child_layer_info(stacking_context: &mut StackingContext) -> Option<LayerInfo> {
+ fn find_last_child_layer_info(self,
+ 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,
- }
+ return self.last_child_layer_info;
}
#[inline]
@@ -926,57 +958,6 @@ impl StackingContextLayerCreator {
Arc::new(PaintLayer::new_with_display_list(layer_info, display_list)));
}
}
-
- #[inline]
- fn add_stacking_context(&mut self,
- stacking_context: Arc<StackingContext>,
- parent_stacking_context: &mut StackingContext) {
- if self.all_following_children_need_layers() || stacking_context.layer_info.is_some() {
- self.add_layered_stacking_context(stacking_context, parent_stacking_context);
- 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);
- }
-
- 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);
-
- // 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,
- color::transparent())));
- 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());
- }
- if let Some(ref mut display_list) = self.display_list_for_next_layer {
- display_list.children.push_back(stacking_context);
- }
- }
}
/// One drawing command in the list.
@@ -989,6 +970,7 @@ pub enum DisplayItem {
GradientClass(Box<GradientDisplayItem>),
LineClass(Box<LineDisplayItem>),
BoxShadowClass(Box<BoxShadowDisplayItem>),
+ StackingContextClass(Arc<StackingContext>),
LayeredItemClass(Box<LayeredItem>),
NoopClass(Box<BaseDisplayItem>),
}
@@ -1436,11 +1418,13 @@ impl<'a> Iterator for DisplayItemIterator<'a> {
impl DisplayItem {
/// Paints this display item into the given painting context.
- fn draw_into_context(&self, paint_context: &mut PaintContext) {
- let this_clip = &self.base().clip;
- match paint_context.transient_clip {
- Some(ref transient_clip) if transient_clip == this_clip => {}
- Some(_) | None => paint_context.push_transient_clip((*this_clip).clone()),
+ fn draw_into_context(&self, transform: &Matrix4, paint_context: &mut PaintContext) {
+ if let Some(base) = self.base() {
+ let this_clip = &base.clip;
+ match paint_context.transient_clip {
+ Some(ref transient_clip) if transient_clip == this_clip => {}
+ Some(_) | None => paint_context.push_transient_clip((*this_clip).clone()),
+ }
}
match *self {
@@ -1491,44 +1475,52 @@ impl DisplayItem {
box_shadow.clip_mode);
}
+ DisplayItem::StackingContextClass(ref stacking_context) => {
+ let pixels_per_px = paint_context.screen_pixels_per_px();
+ let new_transform =
+ transform.translate(stacking_context.bounds
+ .origin
+ .x
+ .to_nearest_pixel(pixels_per_px) as AzFloat,
+ stacking_context.bounds
+ .origin
+ .y
+ .to_nearest_pixel(pixels_per_px) as AzFloat,
+ 0.0);
+ stacking_context.optimize_and_draw_into_context(paint_context,
+ &new_transform,
+ Some(&stacking_context.overflow))
+
+ }
+
DisplayItem::LayeredItemClass(_) => panic!("Found layered item during drawing."),
DisplayItem::NoopClass(_) => { }
}
}
- pub fn base(&self) -> &BaseDisplayItem {
+ pub fn base(&self) -> Option<&BaseDisplayItem> {
match *self {
- DisplayItem::SolidColorClass(ref solid_color) => &solid_color.base,
- DisplayItem::TextClass(ref text) => &text.base,
- DisplayItem::ImageClass(ref image_item) => &image_item.base,
- DisplayItem::BorderClass(ref border) => &border.base,
- DisplayItem::GradientClass(ref gradient) => &gradient.base,
- DisplayItem::LineClass(ref line) => &line.base,
- DisplayItem::BoxShadowClass(ref box_shadow) => &box_shadow.base,
+ DisplayItem::SolidColorClass(ref solid_color) => Some(&solid_color.base),
+ DisplayItem::TextClass(ref text) => Some(&text.base),
+ DisplayItem::ImageClass(ref image_item) => Some(&image_item.base),
+ DisplayItem::BorderClass(ref border) => Some(&border.base),
+ DisplayItem::GradientClass(ref gradient) => Some(&gradient.base),
+ DisplayItem::LineClass(ref line) => Some(&line.base),
+ DisplayItem::BoxShadowClass(ref box_shadow) => Some(&box_shadow.base),
DisplayItem::LayeredItemClass(ref layered_item) => layered_item.item.base(),
- DisplayItem::NoopClass(ref base_item) => base_item,
+ DisplayItem::NoopClass(ref base_item) => Some(base_item),
+ DisplayItem::StackingContextClass(_) => None,
}
}
- pub fn mut_base(&mut self) -> &mut BaseDisplayItem {
+ pub fn bounds(&self) -> Rect<Au> {
match *self {
- DisplayItem::SolidColorClass(ref mut solid_color) => &mut solid_color.base,
- DisplayItem::TextClass(ref mut text) => &mut text.base,
- DisplayItem::ImageClass(ref mut image_item) => &mut image_item.base,
- DisplayItem::BorderClass(ref mut border) => &mut border.base,
- 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,
+ DisplayItem::StackingContextClass(ref stacking_context) => stacking_context.bounds,
+ _ => self.base().unwrap().bounds,
}
}
- pub fn bounds(&self) -> Rect<Au> {
- self.base().bounds
- }
-
pub fn debug_with_level(&self, level: u32) {
let mut indent = String::new();
for _ in 0..level {
@@ -1536,11 +1528,29 @@ impl DisplayItem {
}
println!("{}+ {:?}", indent, self);
}
+
+ fn compare_zindex(&self, other: &DisplayItem) -> Ordering {
+ match (self, other) {
+ (&DisplayItem::StackingContextClass(ref this),
+ &DisplayItem::StackingContextClass(ref other)) => this.z_index.cmp(&other.z_index),
+ (&DisplayItem::StackingContextClass(ref this), _) => this.z_index.cmp(&0),
+ (_, &DisplayItem::StackingContextClass(ref other)) => 0.cmp(&other.z_index),
+ (_, _) => Ordering::Equal,
+ }
+ }
+
+ fn has_negative_z_index(&self) -> bool {
+ if let &DisplayItem::StackingContextClass(ref stacking_context) = self {
+ stacking_context.z_index < 0
+ } else {
+ false
+ }
+ }
}
impl fmt::Debug for DisplayItem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{} @ {:?} ({:x})",
+ write!(f, "{} @ {:?}",
match *self {
DisplayItem::SolidColorClass(ref solid_color) =>
format!("SolidColor rgba({}, {}, {}, {})",
@@ -1554,12 +1564,12 @@ impl fmt::Debug for DisplayItem {
DisplayItem::GradientClass(_) => "Gradient".to_owned(),
DisplayItem::LineClass(_) => "Line".to_owned(),
DisplayItem::BoxShadowClass(_) => "BoxShadow".to_owned(),
+ DisplayItem::StackingContextClass(_) => "StackingContext".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()
+ self.bounds(),
)
}
}
diff --git a/components/gfx/display_list/optimizer.rs b/components/gfx/display_list/optimizer.rs
index cda26de2d96..10abe306549 100644
--- a/components/gfx/display_list/optimizer.rs
+++ b/components/gfx/display_list/optimizer.rs
@@ -40,7 +40,6 @@ impl DisplayListOptimizer {
display_list.positioned_content.iter());
self.add_in_bounds_display_items(&mut result.outlines,
display_list.outlines.iter());
- self.add_in_bounds_stacking_contexts(&mut result.children, display_list.children.iter());
result
}
@@ -50,39 +49,49 @@ impl DisplayListOptimizer {
display_items: I)
where I: Iterator<Item=&'a DisplayItem> {
for display_item in display_items {
- if self.visible_rect.intersects(&display_item.base().bounds) &&
- display_item.base().clip.might_intersect_rect(&self.visible_rect) {
- result_list.push_back((*display_item).clone())
+ if !self.should_include_display_item(display_item) {
+ continue;
}
+ result_list.push_back((*display_item).clone())
}
}
- /// Adds child stacking contexts whose boundaries intersect the visible rect to `result_list`.
- fn add_in_bounds_stacking_contexts<'a, I>(&self,
- result_list: &mut LinkedList<Arc<StackingContext>>,
- stacking_contexts: I)
- where I: Iterator<Item=&'a Arc<StackingContext>> {
- for stacking_context in stacking_contexts {
- // Transform this stacking context to get it into the same space as
- // the parent stacking context.
- let origin_x = stacking_context.bounds.origin.x.to_f32_px();
- let origin_y = stacking_context.bounds.origin.y.to_f32_px();
-
- let transform = Matrix4::identity().translate(origin_x,
- origin_y,
- 0.0)
- .mul(&stacking_context.transform);
- let transform_2d = Matrix2D::new(transform.m11, transform.m12,
- transform.m21, transform.m22,
- transform.m41, transform.m42);
+ fn should_include_display_item(&self, item: &DisplayItem) -> bool {
+ if let &DisplayItem::StackingContextClass(ref stacking_context) = item {
+ return self.should_include_stacking_context(stacking_context);
+ }
- let overflow = geometry::au_rect_to_f32_rect(stacking_context.overflow);
- let overflow = transform_2d.transform_rect(&overflow);
- let overflow = geometry::f32_rect_to_au_rect(overflow);
+ if !self.visible_rect.intersects(&item.bounds()) {
+ return false;
+ }
- if self.visible_rect.intersects(&overflow) {
- result_list.push_back((*stacking_context).clone())
+ if let Some(base_item) = item.base() {
+ if !base_item.clip.might_intersect_rect(&self.visible_rect) {
+ return false;
}
}
+
+ true
+ }
+
+ fn should_include_stacking_context(&self, stacking_context: &Arc<StackingContext>) -> bool {
+ // Transform this stacking context to get it into the same space as
+ // the parent stacking context.
+ let origin_x = stacking_context.bounds.origin.x.to_f32_px();
+ let origin_y = stacking_context.bounds.origin.y.to_f32_px();
+
+ let transform = Matrix4::identity().translate(origin_x,
+ origin_y,
+ 0.0)
+ .mul(&stacking_context.transform);
+ let transform_2d = Matrix2D::new(transform.m11, transform.m12,
+ transform.m21, transform.m22,
+ transform.m41, transform.m42);
+
+ let overflow = geometry::au_rect_to_f32_rect(stacking_context.overflow);
+ let overflow = transform_2d.transform_rect(&overflow);
+ let overflow = geometry::f32_rect_to_au_rect(overflow);
+
+ self.visible_rect.intersects(&overflow)
}
}
diff --git a/components/gfx/paint_task.rs b/components/gfx/paint_task.rs
index 9a5821025a9..331c25a0be2 100644
--- a/components/gfx/paint_task.rs
+++ b/components/gfx/paint_task.rs
@@ -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::{DisplayList, LayerInfo, StackingContext};
+use display_list::{DisplayItem, DisplayList, LayerInfo, StackingContext};
use euclid::Matrix4;
use euclid::point::Point2D;
use euclid::rect::Rect;
@@ -499,13 +499,16 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
transform: &Matrix4,
perspective: &Matrix4,
parent_id: Option<LayerId>) {
- for kid in stacking_context.display_list.children.iter() {
- build_from_stacking_context(properties,
- &kid,
- &parent_origin,
- &transform,
- &perspective,
- parent_id)
+ for kid in stacking_context.display_list.positioned_content.iter() {
+ if let &DisplayItem::StackingContextClass(ref stacking_context) = kid {
+ build_from_stacking_context(properties,
+ &stacking_context,
+ &parent_origin,
+ &transform,
+ &perspective,
+ parent_id)
+
+ }
}
for kid in stacking_context.display_list.layered_children.iter() {
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index f5c9e0dc600..6e89c4b0df6 100644
--- a/components/layout/display_list_builder.rs
+++ b/components/layout/display_list_builder.rs
@@ -81,7 +81,8 @@ impl DisplayListBuildingResult {
match *self {
DisplayListBuildingResult::None => return,
DisplayListBuildingResult::StackingContext(ref mut stacking_context) => {
- display_list.children.push_back((*stacking_context).clone())
+ display_list.positioned_content.push_back(
+ DisplayItem::StackingContextClass((*stacking_context).clone()))
}
DisplayListBuildingResult::Normal(ref mut source_display_list) => {
display_list.append_from(&mut **source_display_list)
@@ -1691,11 +1692,12 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
let stacking_context = match outer_display_list_for_overflow_scroll {
Some(mut outer_display_list) => {
- outer_display_list.children.push_back(self.fragment.create_stacking_context(
- &self.base,
- display_list,
- scroll_policy,
- StackingContextCreationMode::InnerScrollWrapper));
+ outer_display_list.positioned_content.push_back(
+ DisplayItem::StackingContextClass(self.fragment.create_stacking_context(
+ &self.base,
+ display_list,
+ scroll_policy,
+ StackingContextCreationMode::InnerScrollWrapper)));
self.fragment.create_stacking_context(
&self.base,
outer_display_list,
diff --git a/components/layout/flow.rs b/components/layout/flow.rs
index 5be4533dc6a..f64e8b6b409 100644
--- a/components/layout/flow.rs
+++ b/components/layout/flow.rs
@@ -1103,19 +1103,21 @@ impl BaseFlow {
let all_items = match self.display_list_building_result {
DisplayListBuildingResult::None => Vec::new(),
DisplayListBuildingResult::StackingContext(ref stacking_context) => {
- stacking_context.display_list.all_display_items()
+ stacking_context.display_list.flatten()
}
- DisplayListBuildingResult::Normal(ref display_list) => display_list.all_display_items(),
+ DisplayListBuildingResult::Normal(ref display_list) => display_list.flatten(),
};
for item in &all_items {
- let paint_bounds = item.base().clip.clone().intersect_rect(&item.base().bounds);
- if !paint_bounds.might_be_nonempty() {
- continue;
- }
+ if let Some(base_item) = item.base() {
+ let paint_bounds = base_item.clip.clone().intersect_rect(&base_item.bounds);
+ if !paint_bounds.might_be_nonempty() {
+ continue;
+ }
- if bounds.union(&paint_bounds.bounding_rect()) != bounds {
- error!("DisplayList item {:?} outside of Flow overflow ({:?})", item, paint_bounds);
+ if bounds.union(&paint_bounds.bounding_rect()) != bounds {
+ error!("DisplayList item {:?} outside of Flow overflow ({:?})", item, paint_bounds);
+ }
}
}
}
diff --git a/tests/wpt/metadata-css/css21_dev/html4/floats-154.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/floats-154.htm.ini
deleted file mode 100644
index 2c712334d6e..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/floats-154.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[floats-154.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css21_dev/html4/left-offset-position-fixed-001.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/left-offset-position-fixed-001.htm.ini
deleted file mode 100644
index b228b078d55..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/left-offset-position-fixed-001.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[left-offset-position-fixed-001.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css21_dev/html4/max-height-107.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/max-height-107.htm.ini
deleted file mode 100644
index c9bfff0eacd..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/max-height-107.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[max-height-107.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css21_dev/html4/max-height-110.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/max-height-110.htm.ini
deleted file mode 100644
index 21d4e382984..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/max-height-110.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[max-height-110.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css21_dev/html4/min-height-104.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/min-height-104.htm.ini
deleted file mode 100644
index 1fec05c57f0..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/min-height-104.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[min-height-104.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css21_dev/html4/min-height-105.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/min-height-105.htm.ini
deleted file mode 100644
index 165e8dea549..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/min-height-105.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[min-height-105.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/mozilla/tests/css/stacked_layers.html b/tests/wpt/mozilla/tests/css/stacked_layers.html
index 3f7f5cf7ebd..d5c9c017f21 100644
--- a/tests/wpt/mozilla/tests/css/stacked_layers.html
+++ b/tests/wpt/mozilla/tests/css/stacked_layers.html
@@ -22,6 +22,13 @@
<div class="gray box" style="margin-left: 20px; margin-top: 10px; position: absolute; top: 20px; z-index: 5;"> </div>
</div>
+ <!-- These divs should be stacked in tree order, even though the second one
+ initiates a stacking context and the third one does not. -->
+ <div class="test grayest box">
+ <div class="grayer box" style="transform: translateX(10px) translateY(10px);"> </div>
+ <div class="gray box" style="top: -30px; left: 20px; position: relative; "></div>
+ </div>
+
<!-- The z-index of the second box should be ignored since it is not a positioned element.
so these boxes stack in tree order. -->
<div class="test grayest box">
@@ -36,6 +43,16 @@
<div class="gray box" style="position: relative; left: 20px; top: -40px;"> </div>
</div>
+ <!-- Same as the previous test case, but the iframe is now a descendant
+ of the sibling of the second div, instead of a direct sibling. -->
+ <div class="test grayest box">
+ <div>
+ <iframe class="box" style="margin-left: 10px; margin-top: 10px;" src="data:text/html;charset=utf-8;base64,PGh0bWw+PGJvZHkgc3R5bGU9ImJhY2tncm91bmQ6IHJnYig4MCwgODAsIDgwKTsiPjwvYm9keT48L2Rpdj4="></iframe>
+ </div>
+ <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">
diff --git a/tests/wpt/mozilla/tests/css/stacked_layers_ref.html b/tests/wpt/mozilla/tests/css/stacked_layers_ref.html
index b676ca985fc..1a513fb86f1 100644
--- a/tests/wpt/mozilla/tests/css/stacked_layers_ref.html
+++ b/tests/wpt/mozilla/tests/css/stacked_layers_ref.html
@@ -21,6 +21,11 @@
</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; position: absolute; opacity: 0.999;"></div>
<div class="gray box" style="margin-left: 20px; margin-top: 20px; position: relative; opacity: 0.999;"></div>
</div>
@@ -44,5 +49,10 @@
<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>