aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/gfx/display_list/mod.rs1306
-rw-r--r--components/gfx/display_list/optimizer.rs97
-rw-r--r--components/gfx/paint_thread.rs568
-rw-r--r--components/gfx_traits/lib.rs7
-rw-r--r--components/layout/block.rs42
-rw-r--r--components/layout/display_list_builder.rs811
-rw-r--r--components/layout/flex.rs15
-rw-r--r--components/layout/flow.rs66
-rw-r--r--components/layout/fragment.rs32
-rw-r--r--components/layout/inline.rs14
-rw-r--r--components/layout/layout_thread.rs86
-rw-r--r--components/layout/list_item.rs15
-rw-r--r--components/layout/multicol.rs24
-rw-r--r--components/layout/query.rs49
-rw-r--r--components/layout/sequential.rs27
-rw-r--r--components/layout/table.rs17
-rw-r--r--components/layout/table_caption.rs13
-rw-r--r--components/layout/table_cell.rs17
-rw-r--r--components/layout/table_colgroup.rs11
-rw-r--r--components/layout/table_row.rs17
-rw-r--r--components/layout/table_rowgroup.rs13
-rw-r--r--components/layout/table_wrapper.rs13
-rw-r--r--components/layout/traversal.rs6
-rw-r--r--components/layout/webrender_helpers.rs209
-rw-r--r--components/profile/time.rs2
-rw-r--r--components/profile_traits/time.rs1
-rw-r--r--components/util/print_tree.rs6
27 files changed, 1666 insertions, 1818 deletions
diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs
index 763adb9d71a..aa3c974a1d9 100644
--- a/components/gfx/display_list/mod.rs
+++ b/components/gfx/display_list/mod.rs
@@ -16,24 +16,20 @@
use app_units::Au;
use azure::azure::AzFloat;
-use azure::azure_hl::{Color, DrawTarget};
-use display_list::optimizer::DisplayListOptimizer;
+use azure::azure_hl::Color;
use euclid::approxeq::ApproxEq;
use euclid::num::Zero;
+use euclid::rect::TypedRect;
use euclid::{Matrix2D, Matrix4, Point2D, Rect, SideOffsets2D, Size2D};
-use gfx_traits::{color, LayerId, LayerKind, ScrollPolicy};
+use gfx_traits::{LayerId, ScrollPolicy};
use heapsize::HeapSizeOf;
use msg::constellation_msg::PipelineId;
use net_traits::image::base::Image;
use paint_context::PaintContext;
-use paint_thread::{PaintLayerContents, PaintLayer};
use range::Range;
-use self::DisplayItem::*;
-use smallvec::SmallVec;
use std::cmp::Ordering;
-use std::collections::linked_list::{self, LinkedList};
+use std::collections::HashMap;
use std::fmt;
-use std::mem;
use std::sync::Arc;
use style::computed_values::{border_style, cursor, filter, image_rendering, mix_blend_mode};
use style::computed_values::{pointer_events};
@@ -41,9 +37,7 @@ use style::properties::ComputedValues;
use style_traits::cursor::Cursor;
use text::TextRun;
use text::glyph::CharIndex;
-use util::geometry::MAX_RECT;
-use util::linked_list::prepend_from;
-use util::opts;
+use util::geometry::{self, MAX_RECT, ScreenPx};
use util::print_tree::PrintTree;
use webrender_traits::WebGLContextId;
@@ -53,8 +47,6 @@ pub use style::dom::OpaqueNode;
// layout to use.
pub use azure::azure_hl::GradientStop;
-pub mod optimizer;
-
/// The factor that we multiply the blur radius by in order to inflate the boundaries of display
/// items that involve a blur. This ensures that the display item boundaries include all the ink.
pub static BLUR_INFLATION_FACTOR: i32 = 3;
@@ -62,7 +54,7 @@ pub static BLUR_INFLATION_FACTOR: i32 = 3;
/// 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)]
+#[derive(Clone, Copy, HeapSizeOf, Deserialize, Serialize)]
pub struct LayerInfo {
/// The base LayerId of this layer.
pub layer_id: LayerId,
@@ -76,508 +68,414 @@ pub struct LayerInfo {
/// 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,
+
+ /// The color of the background in this layer. Used for unpainted content.
+ pub background_color: Color,
}
impl LayerInfo {
pub fn new(id: LayerId,
scroll_policy: ScrollPolicy,
- subpage_pipeline_id: Option<PipelineId>)
+ subpage_pipeline_id: Option<PipelineId>,
+ background_color: Color)
-> LayerInfo {
LayerInfo {
layer_id: id,
scroll_policy: scroll_policy,
subpage_pipeline_id: subpage_pipeline_id,
next_layer_id: id.companion_layer_id(),
+ background_color: background_color,
}
}
+}
- 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
+#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
+pub struct DisplayListEntry {
+ pub stacking_context_id: StackingContextId,
+ pub section: DisplayListSection,
+ pub item: DisplayItem,
+}
+
+pub struct DisplayListTraversal<'a> {
+ pub display_list: &'a DisplayList,
+ pub current_item_index: usize,
+ pub last_item_index: usize,
+}
+
+impl<'a> DisplayListTraversal<'a> {
+ fn can_draw_item_at_index(&self, index: usize) -> bool {
+ index <= self.last_item_index && index < self.display_list.list.len()
+ }
+
+ pub fn advance(&mut self, context: &StackingContext) -> Option<&'a DisplayListEntry> {
+ if !self.can_draw_item_at_index(self.current_item_index) {
+ return None
+ }
+ if self.display_list.list[self.current_item_index].stacking_context_id != context.id {
+ return None
+ }
+
+ self.current_item_index += 1;
+ Some(&self.display_list.list[self.current_item_index - 1])
}
- 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
+ fn current_item_offset(&self) -> u32 {
+ self.display_list.get_offset_for_item(&self.display_list.list[self.current_item_index])
+ }
+
+ pub fn skip_past_stacking_context(&mut self, stacking_context: &StackingContext) {
+ let next_stacking_context_offset =
+ self.display_list.offsets[&stacking_context.id].outlines + 1;
+ while self.can_draw_item_at_index(self.current_item_index + 1) &&
+ self.current_item_offset() < next_stacking_context_offset {
+ self.current_item_index += 1;
+ }
}
}
-/// Display items that make up a stacking context. "Steps" here refer to the steps in CSS 2.1
-/// Appendix E.
-///
-/// TODO(pcwalton): We could reduce the size of this structure with a more "skip list"-like
-/// structure, omitting several pointers and lengths.
+#[derive(HeapSizeOf, Deserialize, Serialize)]
+pub struct StackingContextOffsets {
+ pub start: u32,
+ pub block_backgrounds_and_borders: u32,
+ pub content: u32,
+ pub outlines: u32,
+}
+
#[derive(HeapSizeOf, Deserialize, Serialize)]
pub struct DisplayList {
- /// The border and backgrounds for the root of this stacking context: steps 1 and 2.
- pub background_and_borders: LinkedList<DisplayItem>,
- /// Borders and backgrounds for block-level descendants: step 4.
- pub block_backgrounds_and_borders: LinkedList<DisplayItem>,
- /// Floats: step 5. These are treated as pseudo-stacking contexts.
- pub floats: LinkedList<DisplayItem>,
- /// All non-positioned content.
- pub content: LinkedList<DisplayItem>,
- /// All positioned content that does not get a stacking context.
- pub positioned_content: LinkedList<DisplayItem>,
- /// Outlines: step 10.
- pub outlines: LinkedList<DisplayItem>,
- /// 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>,
+ pub list: Vec<DisplayListEntry>,
+ pub offsets: HashMap<StackingContextId, StackingContextOffsets>,
+ pub root_stacking_context: StackingContext,
}
impl DisplayList {
- /// Creates a new, empty display list.
- #[inline]
- pub fn new() -> DisplayList {
- DisplayList {
- background_and_borders: LinkedList::new(),
- block_backgrounds_and_borders: LinkedList::new(),
- floats: LinkedList::new(),
- content: LinkedList::new(),
- positioned_content: LinkedList::new(),
- outlines: LinkedList::new(),
- layered_children: LinkedList::new(),
- layer_info: LinkedList::new(),
- }
- }
+ pub fn new(mut root_stacking_context: StackingContext,
+ items: &mut Option<Vec<DisplayListEntry>>)
+ -> DisplayList {
+ let items = match items.take() {
+ Some(items) => items,
+ None => panic!("Tried to create empty display list."),
+ };
- /// Adds the given display item at the specified section of this display list.
- pub fn add_to_section(&mut self, display_item: DisplayItem, section: DisplayListSection) {
- self.get_section_mut(section).push_back(display_item);
- }
+ let mut offsets = HashMap::new();
+ DisplayList::sort_and_count_stacking_contexts(&mut root_stacking_context, &mut offsets, 0);
- /// Creates a new display list which contains a single stacking context.
- #[inline]
- pub fn new_with_stacking_context(stacking_context: Arc<StackingContext>) -> Box<DisplayList> {
- let mut display_list = box DisplayList::new();
- display_list.positioned_content.push_back(
- DisplayItem::StackingContextClass(stacking_context));
+ let mut display_list = DisplayList {
+ list: items,
+ offsets: offsets,
+ root_stacking_context: root_stacking_context,
+ };
+ display_list.sort();
display_list
}
- /// Appends all display items from `other` into `self`, preserving stacking order and emptying
- /// `other` in the process.
- #[inline]
- pub fn append_from(&mut self, other: &mut Option<Box<DisplayList>>) {
- if let Some(mut other) = other.take() {
- self.background_and_borders.append(&mut other.background_and_borders);
- self.block_backgrounds_and_borders.append(&mut other.block_backgrounds_and_borders);
- self.floats.append(&mut other.floats);
- self.content.append(&mut other.content);
- self.positioned_content.append(&mut other.positioned_content);
- self.outlines.append(&mut other.outlines);
- self.layered_children.append(&mut other.layered_children);
- self.layer_info.append(&mut other.layer_info);
+ pub fn get_offset_for_item(&self, item: &DisplayListEntry) -> u32 {
+ let offsets = &self.offsets[&item.stacking_context_id];
+ match item.section {
+ DisplayListSection::BackgroundAndBorders => offsets.start,
+ DisplayListSection::BlockBackgroundsAndBorders =>
+ offsets.block_backgrounds_and_borders,
+ DisplayListSection::Content => offsets.content,
+ DisplayListSection::Outlines => offsets.outlines,
}
}
- /// 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.content);
- prepend_from(&mut self.floats, &mut self.block_backgrounds_and_borders);
- prepend_from(&mut self.floats, &mut self.background_and_borders);
- }
+ fn sort(&mut self) {
+ let mut list = Vec::new();
+ list.append(&mut self.list);
- /// Merges all display items from all non-positioned-content stacking levels to the
- /// positioned-content stacking level.
- #[inline]
- pub fn form_pseudo_stacking_context_for_positioned_content(&mut self) {
- prepend_from(&mut self.positioned_content, &mut self.outlines);
- prepend_from(&mut self.positioned_content, &mut self.content);
- prepend_from(&mut self.positioned_content, &mut self.floats);
- prepend_from(&mut self.positioned_content, &mut self.block_backgrounds_and_borders);
- prepend_from(&mut self.positioned_content, &mut self.background_and_borders);
- }
-
- /// 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 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()),
+ list.sort_by(|a, b| {
+ if a.stacking_context_id == b.stacking_context_id {
+ return a.section.cmp(&b.section);
}
- }
+ self.get_offset_for_item(a).cmp(&self.get_offset_for_item(b))
+ });
- for display_item in &self.background_and_borders {
- flatten_item(&mut result, display_item);
- }
- for display_item in &self.block_backgrounds_and_borders {
- flatten_item(&mut result, display_item);
- }
- for display_item in &self.floats {
- flatten_item(&mut result, display_item);
- }
- for display_item in &self.content {
- flatten_item(&mut result, display_item);
- }
- for display_item in &self.positioned_content {
- flatten_item(&mut result, display_item);
- }
- for display_item in &self.outlines {
- flatten_item(&mut result, display_item);
- }
- result
+ self.list.append(&mut list);
}
- pub fn print(&self, title: String) {
- let mut print_tree = PrintTree::new(title);
+ pub fn print(&self) {
+ let mut print_tree = PrintTree::new("Display List".to_owned());
self.print_with_tree(&mut print_tree);
}
- pub fn print_with_tree(&self, print_tree: &mut PrintTree) {
- fn print_display_list_section(print_tree: &mut PrintTree,
- items: &LinkedList<DisplayItem>,
- title: &str) {
- if items.is_empty() {
- return;
- }
-
- print_tree.new_level(title.to_owned());
- for item in items {
- match item {
- &DisplayItem::StackingContextClass(ref stacking_context) =>
- stacking_context.print_with_tree(print_tree),
- _ => print_tree.add_item(format!("{:?}", item)),
+ fn sort_and_count_stacking_contexts(
+ stacking_context: &mut StackingContext,
+ offsets: &mut HashMap<StackingContextId, StackingContextOffsets>,
+ mut current_offset: u32)
+ -> u32 {
+ stacking_context.children.sort();
+
+ let start_offset = current_offset;
+ let mut block_backgrounds_and_borders_offset = None;
+ let mut content_offset = None;
+
+ for child in stacking_context.children.iter_mut() {
+ if child.z_index >= 0 {
+ if block_backgrounds_and_borders_offset.is_none() {
+ current_offset += 1;
+ block_backgrounds_and_borders_offset = Some(current_offset);
}
- }
- print_tree.end_level();
- }
- print_display_list_section(print_tree,
- &self.background_and_borders,
- "Backgrounds and Borders");
- print_display_list_section(print_tree,
- &self.block_backgrounds_and_borders,
- "Block Backgrounds and Borders");
- print_display_list_section(print_tree, &self.floats, "Floats");
- print_display_list_section(print_tree, &self.content, "Content");
- print_display_list_section(print_tree, &self.positioned_content, "Positioned Content");
- print_display_list_section(print_tree, &self.outlines, "Outlines");
-
- if !self.layered_children.is_empty() {
- print_tree.new_level("Layers".to_owned());
- for paint_layer in &self.layered_children {
- match paint_layer.contents {
- PaintLayerContents::StackingContext(ref stacking_context) =>
- stacking_context.print_with_tree(print_tree),
- PaintLayerContents::DisplayList(ref display_list) => {
- print_tree.new_level(format!("DisplayList Layer with bounds {:?}:",
- display_list.calculate_bounding_rect()));
- display_list.print_with_tree(print_tree);
- print_tree.end_level();
- }
+ if child.context_type != StackingContextType::PseudoFloat &&
+ content_offset.is_none() {
+ current_offset += 1;
+ content_offset = Some(current_offset);
}
}
- print_tree.end_level();
- }
- }
-
- /// Draws the DisplayList in stacking context order according to the steps in CSS 2.1 § E.2.
- pub fn draw_into_context(&self,
- draw_target: &DrawTarget,
- paint_context: &mut PaintContext,
- transform: &Matrix4,
- clip_rect: Option<&Rect<Au>>) {
- let mut paint_subcontext = PaintContext {
- draw_target: draw_target.clone(),
- font_context: &mut *paint_context.font_context,
- page_rect: paint_context.page_rect,
- screen_rect: paint_context.screen_rect,
- clip_rect: clip_rect.map(|clip_rect| *clip_rect),
- transient_clip: None,
- layer_kind: paint_context.layer_kind,
- };
-
- if opts::get().dump_display_list_optimized {
- self.print(format!("Optimized display list. Tile bounds: {:?}",
- paint_context.page_rect));
- }
-
- // Set up our clip rect and transform.
- let old_transform = paint_subcontext.draw_target.get_transform();
- let xform_2d = Matrix2D::new(transform.m11, transform.m12,
- transform.m21, transform.m22,
- transform.m41, transform.m42);
- paint_subcontext.draw_target.set_transform(&xform_2d);
- paint_subcontext.push_clip_if_applicable();
-
- // Steps 1 and 2: Borders and background for the root.
- for display_item in &self.background_and_borders {
- display_item.draw_into_context(transform, &mut paint_subcontext)
- }
- // Step 3: Positioned descendants with negative z-indices.
- 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);
- }
- }
+ current_offset += 1;
+ current_offset =
+ DisplayList::sort_and_count_stacking_contexts(child, offsets, current_offset);
}
- // Step 4: Block backgrounds and borders.
- for display_item in &self.block_backgrounds_and_borders {
- display_item.draw_into_context(transform, &mut paint_subcontext)
- }
+ let block_backgrounds_and_borders_offset =
+ block_backgrounds_and_borders_offset.unwrap_or_else(|| {
+ current_offset += 1;
+ current_offset
+ });
- // Step 5: Floats.
- for display_item in &self.floats {
- display_item.draw_into_context(transform, &mut paint_subcontext)
- }
+ let content_offset = content_offset.unwrap_or_else(|| {
+ current_offset += 1;
+ current_offset
+ });
- // TODO(pcwalton): Step 6: Inlines that generate stacking contexts.
+ current_offset += 1;
- // Step 7: Content.
- for display_item in &self.content {
- display_item.draw_into_context(transform, &mut paint_subcontext)
- }
+ offsets.insert(
+ stacking_context.id,
+ StackingContextOffsets {
+ start: start_offset,
+ block_backgrounds_and_borders: block_backgrounds_and_borders_offset,
+ content: content_offset,
+ outlines: current_offset,
+ });
- // 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;
- }
- }
- positioned_kid.draw_into_context(transform, &mut paint_subcontext);
- }
+ current_offset + 1
+ }
- // Step 10: Outlines.
- for display_item in &self.outlines {
- display_item.draw_into_context(transform, &mut paint_subcontext)
+ pub fn print_with_tree(&self, print_tree: &mut PrintTree) {
+ print_tree.new_level("Items".to_owned());
+ for item in &self.list {
+ print_tree.add_item(format!("{:?} StackingContext: {:?}",
+ item.item,
+ item.stacking_context_id));
}
+ print_tree.end_level();
- // Undo our clipping and transform.
- paint_subcontext.remove_transient_clip_if_applicable();
- paint_subcontext.pop_clip_if_applicable();
- paint_subcontext.draw_target.set_transform(&old_transform)
+ print_tree.new_level("Stacking Contexts".to_owned());
+ self.root_stacking_context.print_with_tree(print_tree);
+ print_tree.end_level();
}
- pub fn hit_test(&self,
- point: Point2D<Au>,
- result: &mut Vec<DisplayItemMetadata>,
- topmost_only: bool) {
- 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 !base_item.clip.might_intersect_point(&point) {
- // Clipped out.
- return;
- }
- if !item.bounds().contains(&point) {
- // Can't possibly hit.
- return;
- }
- if base_item.metadata.pointing.is_none() {
- // `pointer-events` is `none`. Ignore this item.
- return;
- }
-
- match *item {
- DisplayItem::BorderClass(ref border) => {
- // If the point is inside the border, it didn't hit the border!
- let interior_rect =
- Rect::new(
- Point2D::new(border.base.bounds.origin.x +
- border.border_widths.left,
- border.base.bounds.origin.y +
- border.border_widths.top),
- Size2D::new(border.base.bounds.size.width -
- (border.border_widths.left +
- border.border_widths.right),
- border.base.bounds.size.height -
- (border.border_widths.top +
- border.border_widths.bottom)));
- if interior_rect.contains(&point) {
- return;
- }
- }
- DisplayItem::BoxShadowClass(_) => {
- // Box shadows can never be hit.
- return
- }
- _ => {}
- }
+ /// Draws a single DisplayItem into the given PaintContext.
+ pub fn draw_item_at_index_into_context(&self,
+ paint_context: &mut PaintContext,
+ transform: &Matrix4,
+ index: usize) {
+ let old_transform = paint_context.draw_target.get_transform();
+ paint_context.draw_target.set_transform(
+ &Matrix2D::new(transform.m11, transform.m12,
+ transform.m21, transform.m22,
+ transform.m41, transform.m42));
+
+ let entry = &self.list[index];
+ entry.item.draw_into_context(paint_context);
+
+ paint_context.draw_target.set_transform(&old_transform);
+ }
- // We found a hit!
- result.push(base_item.metadata);
+ pub fn find_stacking_context<'a>(&'a self,
+ stacking_context_id: StackingContextId)
+ -> Option<&'a StackingContext> {
+ fn find_stacking_context_in_stacking_context<'a>(stacking_context: &'a StackingContext,
+ stacking_context_id: StackingContextId)
+ -> Option<&'a StackingContext> {
+ if stacking_context.id == stacking_context_id {
+ return Some(stacking_context);
}
- 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;
+ for kid in stacking_context.children.iter() {
+ let result = find_stacking_context_in_stacking_context(kid, stacking_context_id);
+ if result.is_some() {
+ return result;
}
}
- }
-
- // Layers that are positioned on top of this layer should get a shot at the hit test first.
- for layer in self.layered_children.iter().rev() {
- match layer.contents {
- PaintLayerContents::StackingContext(ref stacking_context) =>
- stacking_context.hit_test(point, result, topmost_only),
- PaintLayerContents::DisplayList(ref display_list) =>
- display_list.hit_test(point, result, topmost_only),
- }
- if topmost_only && !result.is_empty() {
- return
- }
+ None
}
+ find_stacking_context_in_stacking_context(&self.root_stacking_context,
+ stacking_context_id)
+ }
- // Iterate through display items in reverse stacking order. Steps here refer to the
- // painting steps in CSS 2.1 Appendix E.
- //
- // Step 10: Outlines.
- hit_test_in_list(point, result, topmost_only, self.outlines.iter().rev());
- if topmost_only && !result.is_empty() {
- return
- }
+ /// Draws the DisplayList in order.
+ pub fn draw_into_context<'a>(&self,
+ paint_context: &mut PaintContext,
+ transform: &Matrix4,
+ stacking_context_id: StackingContextId,
+ start: usize,
+ end: usize) {
+ let stacking_context = self.find_stacking_context(stacking_context_id).unwrap();
+ let mut traversal = DisplayListTraversal {
+ display_list: self,
+ current_item_index: start,
+ last_item_index: end,
+ };
+ self.draw_stacking_context(stacking_context, &mut traversal, paint_context, transform);
+ }
- // Steps 9 and 8: Positioned descendants with nonnegative z-indices.
- for kid in self.positioned_content.iter().rev() {
- if let &DisplayItem::StackingContextClass(ref stacking_context) = kid {
- if stacking_context.z_index < 0 {
- continue
+ fn draw_stacking_context_contents<'a>(&'a self,
+ stacking_context: &StackingContext,
+ traversal: &mut DisplayListTraversal<'a>,
+ paint_context: &mut PaintContext,
+ transform: &Matrix4,
+ tile_rect: Option<Rect<Au>>) {
+ for child in stacking_context.children.iter() {
+ while let Some(item) = traversal.advance(stacking_context) {
+ if item.item.intersects_rect_in_parent_context(tile_rect) {
+ item.item.draw_into_context(paint_context);
}
- stacking_context.hit_test(point, result, topmost_only);
- } else {
- hit_test_item(point, result, kid);
- }
-
- if topmost_only && !result.is_empty() {
- return
}
- }
- // Steps 8, 7, 5, and 4: Positioned content, content, floats, and block backgrounds and
- // borders.
- //
- // TODO(pcwalton): Step 6: Inlines that generate stacking contexts.
- for display_list in &[
- &self.content,
- &self.floats,
- &self.block_backgrounds_and_borders,
- ] {
- hit_test_in_list(point, result, topmost_only, display_list.iter().rev());
- if topmost_only && !result.is_empty() {
- return
+ if child.intersects_rect_in_parent_context(tile_rect) {
+ self.draw_stacking_context(child, traversal, paint_context, &transform);
+ } else {
+ traversal.skip_past_stacking_context(child);
}
}
- 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
- }
+ while let Some(item) = traversal.advance(stacking_context) {
+ if item.item.intersects_rect_in_parent_context(tile_rect) {
+ item.item.draw_into_context(paint_context);
}
}
-
- // Steps 2 and 1: Borders and background for the root.
- hit_test_in_list(point,
- result,
- topmost_only,
- self.background_and_borders.iter().rev())
-
}
- /// Returns the PaintLayer in the given DisplayList with a specific layer ID.
- pub fn find_layer_with_layer_id(&self, layer_id: LayerId) -> Option<Arc<PaintLayer>> {
- for kid in &self.layered_children {
- if let Some(paint_layer) = PaintLayer::find_layer_with_layer_id(&kid, 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);
- }
- }
+ fn draw_stacking_context<'a>(&'a self,
+ stacking_context: &StackingContext,
+ traversal: &mut DisplayListTraversal<'a>,
+ paint_context: &mut PaintContext,
+ transform: &Matrix4) {
+
+ if stacking_context.context_type != StackingContextType::Real {
+ self.draw_stacking_context_contents(stacking_context,
+ traversal,
+ paint_context,
+ transform,
+ None);
+ return;
}
- None
- }
+ let draw_target = paint_context.get_or_create_temporary_draw_target(
+ &stacking_context.filters,
+ stacking_context.blend_mode);
- /// Calculate the union of all the bounds of all of the items in this display list.
- /// This is an expensive operation, so it shouldn't be done unless absolutely necessary
- /// and, if possible, the result should be cached.
- 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.bounds());
+ // If a layer is being used, the transform for this layer
+ // will be handled by the compositor.
+ let old_transform = paint_context.draw_target.get_transform();
+ let transform = match stacking_context.layer_info {
+ Some(..) => *transform,
+ None => {
+ let pixels_per_px = paint_context.screen_pixels_per_px();
+ let origin = &stacking_context.bounds.origin;
+ transform.translate(
+ origin.x.to_nearest_pixel(pixels_per_px.get()) as AzFloat,
+ origin.y.to_nearest_pixel(pixels_per_px.get()) as AzFloat,
+ 0.0).mul(&stacking_context.transform)
}
- bounds
};
- let mut bounds = Rect::zero();
- bounds = union_all_items(&self.background_and_borders, bounds);
- bounds = union_all_items(&self.block_backgrounds_and_borders, bounds);
- bounds = union_all_items(&self.floats, bounds);
- bounds = union_all_items(&self.content, bounds);
- bounds = union_all_items(&self.positioned_content, bounds);
- bounds = union_all_items(&self.outlines, bounds);
- bounds
+ {
+ let mut paint_subcontext = PaintContext {
+ draw_target: draw_target.clone(),
+ font_context: &mut *paint_context.font_context,
+ page_rect: paint_context.page_rect,
+ screen_rect: paint_context.screen_rect,
+ clip_rect: Some(stacking_context.overflow),
+ transient_clip: None,
+ layer_kind: paint_context.layer_kind,
+ };
+
+ // Set up our clip rect and transform.
+ paint_subcontext.draw_target.set_transform(
+ &Matrix2D::new(transform.m11, transform.m12,
+ transform.m21, transform.m22,
+ transform.m41, transform.m42));
+ paint_subcontext.push_clip_if_applicable();
+
+ self.draw_stacking_context_contents(
+ stacking_context,
+ traversal,
+ &mut paint_subcontext,
+ &transform,
+ Some(transformed_tile_rect(paint_context.screen_rect, &transform)));
+
+ paint_subcontext.remove_transient_clip_if_applicable();
+ paint_subcontext.pop_clip_if_applicable();
+ }
+
+ draw_target.set_transform(&old_transform);
+ paint_context.draw_temporary_draw_target_if_necessary(
+ &draw_target, &stacking_context.filters, stacking_context.blend_mode);
}
- #[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,
- }
+ /// Places all nodes containing the point of interest into `result`, topmost first. Respects
+ /// the `pointer-events` CSS property If `topmost_only` is true, stops after placing one node
+ /// into the list. `result` must be empty upon entry to this function.
+ pub fn hit_test(&self, point: Point2D<Au>) -> Vec<DisplayItemMetadata> {
+ let mut traversal = DisplayListTraversal {
+ display_list: self,
+ current_item_index: 0,
+ last_item_index: self.list.len() - 1,
+ };
+ let mut result = Vec::new();
+ self.root_stacking_context.hit_test(&mut traversal, point, &mut result);
+ result.reverse();
+ result
}
}
-#[derive(Clone, Copy, Debug)]
+fn transformed_tile_rect(tile_rect: TypedRect<ScreenPx, usize>, transform: &Matrix4) -> Rect<Au> {
+ // Invert the current transform, then use this to back transform
+ // the tile rect (placed at the origin) into the space of this
+ // stacking context.
+ let inverse_transform = transform.invert();
+ let inverse_transform_2d = Matrix2D::new(inverse_transform.m11, inverse_transform.m12,
+ inverse_transform.m21, inverse_transform.m22,
+ inverse_transform.m41, inverse_transform.m42);
+ let tile_size = Size2D::new(tile_rect.as_f32().size.width, tile_rect.as_f32().size.height);
+ let tile_rect = Rect::new(Point2D::zero(), tile_size).to_untyped();
+ geometry::f32_rect_to_au_rect(inverse_transform_2d.transform_rect(&tile_rect))
+}
+
+
+/// Display list sections that make up a stacking context. Each section here refers
+/// to the steps in CSS 2.1 Appendix E.
+///
+#[derive(Clone, Copy, Debug, Deserialize, Eq, HeapSizeOf, Ord, PartialEq, PartialOrd, RustcEncodable, Serialize)]
pub enum DisplayListSection {
BackgroundAndBorders,
BlockBackgroundsAndBorders,
- Floats,
Content,
- PositionedContent,
Outlines,
}
+#[derive(Clone, Copy, Debug, Deserialize, Eq, HeapSizeOf, Ord, PartialEq, PartialOrd, RustcEncodable, Serialize)]
+pub enum StackingContextType {
+ Real,
+ PseudoPositioned,
+ PseudoFloat,
+}
+
#[derive(HeapSizeOf, Deserialize, Serialize)]
/// Represents one CSS stacking context, which may or may not have a hardware layer.
pub struct StackingContext {
- /// The display items that make up this stacking context.
- pub display_list: Box<DisplayList>,
+ /// The ID of this StackingContext for uniquely identifying it.
+ pub id: StackingContextId,
+
+ /// The type of this StackingContext. Used for collecting and sorting.
+ pub context_type: StackingContextType,
/// The position and size of this stacking context.
pub bounds: Rect<Au>,
@@ -609,14 +507,15 @@ 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>,
+ /// Children of this StackingContext.
+ pub children: Vec<StackingContext>,
}
impl StackingContext {
/// Creates a new stacking context.
#[inline]
- pub fn new(display_list: Box<DisplayList>,
+ pub fn new(id: StackingContextId,
+ context_type: StackingContextType,
bounds: &Rect<Au>,
overflow: &Rect<Au>,
z_index: i32,
@@ -628,8 +527,9 @@ impl StackingContext {
scrolls_overflow_area: bool,
layer_info: Option<LayerInfo>)
-> StackingContext {
- let mut stacking_context = StackingContext {
- display_list: display_list,
+ StackingContext {
+ id: id,
+ context_type: context_type,
bounds: *bounds,
overflow: *overflow,
z_index: z_index,
@@ -640,334 +540,121 @@ impl StackingContext {
establishes_3d_context: establishes_3d_context,
scrolls_overflow_area: scrolls_overflow_area,
layer_info: layer_info,
- last_child_layer_info: None,
- };
- // webrender doesn't care about layers in the display list - it's handled internally.
- if !opts::get().use_webrender {
- StackingContextLayerCreator::add_layers_to_preserve_drawing_order(&mut stacking_context);
- }
- stacking_context
- }
-
- /// 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,
- paint_context: &mut PaintContext,
- transform: &Matrix4,
- clip_rect: Option<&Rect<Au>>) {
- let temporary_draw_target =
- paint_context.get_or_create_temporary_draw_target(&self.filters, self.blend_mode);
-
- display_list.draw_into_context(&temporary_draw_target,
- paint_context,
- transform,
- clip_rect);
-
- paint_context.draw_temporary_draw_target_if_necessary(&temporary_draw_target,
- &self.filters,
- self.blend_mode)
-
- }
-
- /// Optionally optimize and then draws the stacking context.
- pub fn optimize_and_draw_into_context(&self,
- paint_context: &mut PaintContext,
- transform: &Matrix4,
- clip_rect: Option<&Rect<Au>>) {
-
- // If a layer is being used, the transform for this layer
- // will be handled by the compositor.
- let transform = match self.layer_info {
- Some(..) => *transform,
- None => transform.mul(&self.transform),
- };
-
- // TODO(gw): This is a hack to avoid running the DL optimizer
- // on 3d transformed tiles. We should have a better solution
- // than just disabling the opts here.
- if paint_context.layer_kind == LayerKind::HasTransform ||
- opts::get().use_webrender { // webrender takes care of all culling via aabb tree!
- self.draw_into_context(&self.display_list,
- paint_context,
- &transform,
- clip_rect);
-
- } else {
- // Invert the current transform, then use this to back transform
- // the tile rect (placed at the origin) into the space of this
- // stacking context.
- let inverse_transform = transform.invert();
- let inverse_transform_2d = Matrix2D::new(inverse_transform.m11, inverse_transform.m12,
- inverse_transform.m21, inverse_transform.m22,
- inverse_transform.m41, inverse_transform.m42);
-
- let tile_size = Size2D::new(paint_context.screen_rect.as_f32().size.width,
- paint_context.screen_rect.as_f32().size.height);
- let tile_rect = Rect::new(Point2D::zero(), tile_size).to_untyped();
- let tile_rect = inverse_transform_2d.transform_rect(&tile_rect);
-
- // Optimize the display list to throw out out-of-bounds display items and so forth.
- let display_list = DisplayListOptimizer::new(&tile_rect).optimize(&*self.display_list);
-
- self.draw_into_context(&display_list,
- paint_context,
- &transform,
- clip_rect);
+ children: Vec::new(),
}
}
- /// Places all nodes containing the point of interest into `result`, topmost first. Respects
- /// the `pointer-events` CSS property If `topmost_only` is true, stops after placing one node
- /// into the list. `result` must be empty upon entry to this function.
- pub fn hit_test(&self,
- point: Point2D<Au>,
- result: &mut Vec<DisplayItemMetadata>,
- topmost_only: bool) {
+ pub fn hit_test<'a>(&self,
+ traversal: &mut DisplayListTraversal<'a>,
+ point: Point2D<Au>,
+ result: &mut Vec<DisplayItemMetadata>) {
// Convert the point into stacking context local space
- let point = point - self.bounds.origin;
-
- debug_assert!(!topmost_only || result.is_empty());
- let inv_transform = self.transform.invert();
- let frac_point = inv_transform.transform_point(&Point2D::new(point.x.to_f32_px(),
- point.y.to_f32_px()));
- let point = Point2D::new(Au::from_f32_px(frac_point.x), Au::from_f32_px(frac_point.y));
- self.display_list.hit_test(point, result, topmost_only)
- }
-
- pub fn print(&self, title: String) {
- let mut print_tree = PrintTree::new(title);
- self.print_with_tree(&mut print_tree);
- }
-
- fn print_with_tree(&self, print_tree: &mut PrintTree) {
- if self.layer_info.is_some() {
- print_tree.new_level(format!("Layered StackingContext at {:?} with overflow {:?}:",
- self.bounds,
- self.overflow));
+ let point = if self.context_type == StackingContextType::Real {
+ let point = point - self.bounds.origin;
+ let inv_transform = self.transform.invert();
+ let frac_point = inv_transform.transform_point(&Point2D::new(point.x.to_f32_px(),
+ point.y.to_f32_px()));
+ Point2D::new(Au::from_f32_px(frac_point.x), Au::from_f32_px(frac_point.y))
} else {
- print_tree.new_level(format!("StackingContext at {:?} with 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,
- }
- }
+ point
+ };
- 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;
+ for child in self.children.iter() {
+ while let Some(item) = traversal.advance(self) {
+ item.item.hit_test(point, result);
}
+ child.hit_test(traversal, point, result);
}
- 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,
- last_child_layer_info: Option<LayerInfo>,
-}
-
-impl StackingContextLayerCreator {
- fn new() -> StackingContextLayerCreator {
- // webrender doesn't care about layers in the display list - it's handled internally.
- debug_assert!(!opts::get().use_webrender);
-
- StackingContextLayerCreator {
- display_list_for_next_layer: None,
- next_layer_info: None,
- building_ordering_layer: false,
- last_child_layer_info: None,
+ while let Some(item) = traversal.advance(self) {
+ item.item.hit_test(point, result);
}
}
- #[inline]
- 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);
-
- for item in remaining_positioned_content.into_iter() {
- assert!(!item.has_negative_z_index());
- state.add_display_item(item, DisplayListSection::PositionedContent, stacking_context);
+ pub fn print_with_tree(&self, print_tree: &mut PrintTree) {
+ print_tree.new_level(format!("{:?}", self));
+ for kid in self.children.iter() {
+ kid.print_with_tree(print_tree);
}
-
- 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);
+ print_tree.end_level();
}
- #[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);
+ pub fn intersects_rect_in_parent_context(&self, rect: Option<Rect<Au>>) -> bool {
+ // We only do intersection checks for real stacking contexts, since
+ // pseudo stacking contexts might not have proper position information.
+ if self.context_type != StackingContextType::Real {
+ return true;
}
- }
- #[inline]
- fn all_following_children_need_layers(&self) -> bool {
- self.next_layer_info.is_some()
- }
+ let rect = match rect {
+ Some(ref rect) => rect,
+ None => return true,
+ };
- #[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(),
- }
- }
+ // Transform this stacking context to get it into the same space as
+ // the parent stacking context.
+ let origin_x = self.bounds.origin.x.to_f32_px();
+ let origin_y = self.bounds.origin.y.to_f32_px();
- #[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 transform = Matrix4::identity().translate(origin_x,
+ origin_y,
+ 0.0)
+ .mul(&self.transform);
+ let transform_2d = Matrix2D::new(transform.m11, transform.m12,
+ transform.m21, transform.m22,
+ transform.m41, transform.m42);
- 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;
+ let overflow = geometry::au_rect_to_f32_rect(self.overflow);
+ let overflow = transform_2d.transform_rect(&overflow);
+ let overflow = geometry::f32_rect_to_au_rect(overflow);
- self.building_ordering_layer = true;
+ rect.intersects(&overflow)
}
+}
- fn add_display_item(&mut self,
- item: DisplayItem,
- section: DisplayListSection,
- parent_stacking_context: &mut StackingContext) {
- if !self.display_item_needs_layer(&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.add_to_section(item, section);
- return;
+impl Ord for StackingContext {
+ fn cmp(&self, other: &Self) -> Ordering {
+ if self.z_index != 0 || other.z_index != 0 {
+ return self.z_index.cmp(&other.z_index);
}
- 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(parent_stacking_context);
- self.building_ordering_layer = false;
- 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 (self.context_type, other.context_type) {
+ (StackingContextType::PseudoFloat, StackingContextType::PseudoFloat) => Ordering::Equal,
+ (StackingContextType::PseudoFloat, _) => Ordering::Less,
+ (_, StackingContextType::PseudoFloat) => Ordering::Greater,
+ (_, _) => Ordering::Equal,
}
-
- 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,
- 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.add_to_section(item, section);
- }
+impl PartialOrd for StackingContext {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
}
+}
- 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));
- }
-
- self.last_child_layer_info
+impl Eq for StackingContext {}
+impl PartialEq for StackingContext {
+ fn eq(&self, other: &Self) -> bool {
+ self.id == other.id
}
+}
- #[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();
- stacking_context.display_list.layered_children.push_back(
- Arc::new(PaintLayer::new_with_display_list(layer_info, display_list)));
- }
+impl fmt::Debug for StackingContext {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let type_string = if self.layer_info.is_some() {
+ "Layered StackingContext"
+ } else if self.context_type == StackingContextType::Real {
+ "StackingContext"
+ } else {
+ "Pseudo-StackingContext"
+ };
+
+ write!(f, "{} at {:?} with overflow {:?}: {:?}",
+ type_string,
+ self.bounds,
+ self.overflow,
+ self.id)
}
}
@@ -982,7 +669,6 @@ pub enum DisplayItem {
GradientClass(Box<GradientDisplayItem>),
LineClass(Box<LineDisplayItem>),
BoxShadowClass(Box<BoxShadowDisplayItem>),
- StackingContextClass(Arc<StackingContext>),
LayeredItemClass(Box<LayeredItem>),
NoopClass(Box<BaseDisplayItem>),
IframeClass(Box<IframeDisplayItem>),
@@ -1003,7 +689,9 @@ pub struct BaseDisplayItem {
impl BaseDisplayItem {
#[inline(always)]
- pub fn new(bounds: &Rect<Au>, metadata: DisplayItemMetadata, clip: &ClippingRegion)
+ pub fn new(bounds: &Rect<Au>,
+ metadata: DisplayItemMetadata,
+ clip: &ClippingRegion)
-> BaseDisplayItem {
// Detect useless clipping regions here and optimize them to `ClippingRegion::max()`.
// The painting backend may want to optimize out clipping regions and this makes it easier
@@ -1011,7 +699,7 @@ impl BaseDisplayItem {
BaseDisplayItem {
bounds: *bounds,
metadata: metadata,
- clip: if clip.does_not_clip_rect(bounds) {
+ clip: if clip.does_not_clip_rect(&bounds) {
ClippingRegion::max()
} else {
(*clip).clone()
@@ -1020,7 +708,6 @@ impl BaseDisplayItem {
}
}
-
/// A clipping region for a display item. Currently, this can describe rectangles, rounded
/// rectangles (for `border-radius`), or arbitrary intersections of the two. Arbitrary transforms
/// are not supported because those are handled by the higher-level `StackingContext` abstraction.
@@ -1412,6 +1099,9 @@ pub struct LayeredItem {
/// The id of the layer this item belongs to.
pub layer_id: LayerId,
+
+ /// The id of the layer this item belongs to.
+ pub layer_info: LayerInfo,
}
/// How a box shadow should be clipped.
@@ -1427,31 +1117,13 @@ pub enum BoxShadowClipMode {
Inset,
}
-pub enum DisplayItemIterator<'a> {
- Empty,
- Parent(linked_list::Iter<'a, DisplayItem>),
-}
-
-impl<'a> Iterator for DisplayItemIterator<'a> {
- type Item = &'a DisplayItem;
- #[inline]
- fn next(&mut self) -> Option<&'a DisplayItem> {
- match *self {
- DisplayItemIterator::Empty => None,
- DisplayItemIterator::Parent(ref mut subiterator) => subiterator.next(),
- }
- }
-}
-
impl DisplayItem {
/// Paints this display item into the given painting context.
- 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()),
- }
+ 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()),
}
match *self {
@@ -1506,53 +1178,44 @@ 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.get()) as AzFloat,
- stacking_context.bounds
- .origin
- .y
- .to_nearest_pixel(pixels_per_px.get()) 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::LayeredItemClass(ref item) => item.item.draw_into_context(paint_context),
DisplayItem::NoopClass(_) => { }
DisplayItem::IframeClass(..) => {}
}
}
- pub fn base(&self) -> Option<&BaseDisplayItem> {
+ pub fn intersects_rect_in_parent_context(&self, rect: Option<Rect<Au>>) -> bool {
+ let rect = match rect {
+ Some(ref rect) => rect,
+ None => return true,
+ };
+
+ if !rect.intersects(&self.bounds()) {
+ return false;
+ }
+
+ self.base().clip.might_intersect_rect(&rect)
+ }
+
+ pub fn base(&self) -> &BaseDisplayItem {
match *self {
- 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::WebGLClass(ref webgl_item) => Some(&webgl_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::SolidColorClass(ref solid_color) => &solid_color.base,
+ DisplayItem::TextClass(ref text) => &text.base,
+ DisplayItem::ImageClass(ref image_item) => &image_item.base,
+ DisplayItem::WebGLClass(ref webgl_item) => &webgl_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::LayeredItemClass(ref layered_item) => layered_item.item.base(),
- DisplayItem::NoopClass(ref base_item) => Some(base_item),
- DisplayItem::StackingContextClass(_) => None,
- DisplayItem::IframeClass(ref iframe) => Some(&iframe.base),
+ DisplayItem::NoopClass(ref base_item) => base_item,
+ DisplayItem::IframeClass(ref iframe) => &iframe.base,
}
}
pub fn bounds(&self) -> Rect<Au> {
- match *self {
- DisplayItem::StackingContextClass(ref stacking_context) => stacking_context.bounds,
- _ => self.base().unwrap().bounds,
- }
+ self.base().bounds
}
pub fn debug_with_level(&self, level: u32) {
@@ -1563,22 +1226,44 @@ 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 hit_test(&self, point: Point2D<Au>, result: &mut Vec<DisplayItemMetadata>) {
+ // TODO(pcwalton): Use a precise algorithm here. This will allow us to properly hit
+ // test elements with `border-radius`, for example.
+ let base_item = self.base();
+ if !base_item.clip.might_intersect_point(&point) {
+ // Clipped out.
+ return;
+ }
+ if !self.bounds().contains(&point) {
+ // Can't possibly hit.
+ return;
+ }
+ if base_item.metadata.pointing.is_none() {
+ // `pointer-events` is `none`. Ignore this item.
+ return;
}
- }
- fn has_negative_z_index(&self) -> bool {
- if let &DisplayItem::StackingContextClass(ref stacking_context) = self {
- stacking_context.z_index < 0
- } else {
- false
+ if let DisplayItem::BorderClass(ref border) = *self {
+ // If the point is inside the border, it didn't hit the border!
+ let interior_rect =
+ Rect::new(
+ Point2D::new(border.base.bounds.origin.x +
+ border.border_widths.left,
+ border.base.bounds.origin.y +
+ border.border_widths.top),
+ Size2D::new(border.base.bounds.size.width -
+ (border.border_widths.left +
+ border.border_widths.right),
+ border.base.bounds.size.height -
+ (border.border_widths.top +
+ border.border_widths.bottom)));
+ if interior_rect.contains(&point) {
+ return;
+ }
}
+
+ // We found a hit!
+ result.push(base_item.metadata);
}
}
@@ -1599,7 +1284,6 @@ 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(),
@@ -1609,3 +1293,33 @@ impl fmt::Debug for DisplayItem {
)
}
}
+
+#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Deserialize, Serialize, HeapSizeOf, RustcEncodable)]
+pub enum FragmentType {
+ /// A StackingContext for the fragment body itself.
+ FragmentBody,
+ /// A StackingContext created to contain ::before pseudo-element content.
+ BeforePseudoContent,
+ /// A StackingContext created to contain ::after pseudo-element content.
+ AfterPseudoContent,
+}
+
+/// A unique ID for every stacking context.
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, HeapSizeOf, PartialEq, RustcEncodable, Serialize)]
+pub struct StackingContextId(
+ /// The type of the fragment for this StackingContext. This serves to differentiate
+ /// StackingContexts that share fragments.
+ FragmentType,
+ /// The identifier for this StackingContexts, derived from the Flow's memory address.
+ usize
+);
+
+impl StackingContextId {
+ pub fn new(id: usize) -> StackingContextId {
+ StackingContextId(FragmentType::FragmentBody, id)
+ }
+
+ pub fn new_of_type(id: usize, fragment_type: FragmentType) -> StackingContextId {
+ StackingContextId(fragment_type, id)
+ }
+}
diff --git a/components/gfx/display_list/optimizer.rs b/components/gfx/display_list/optimizer.rs
deleted file mode 100644
index 10abe306549..00000000000
--- a/components/gfx/display_list/optimizer.rs
+++ /dev/null
@@ -1,97 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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/. */
-
-//! Transforms a display list to produce a visually-equivalent, but cheaper-to-paint, one.
-
-use app_units::Au;
-use display_list::{DisplayItem, DisplayList, StackingContext};
-use euclid::rect::Rect;
-use euclid::{Matrix2D, Matrix4};
-use std::collections::linked_list::LinkedList;
-use std::sync::Arc;
-use util::geometry;
-
-/// Transforms a display list to produce a visually-equivalent, but cheaper-to-paint, one.
-pub struct DisplayListOptimizer {
- /// The visible rect in page coordinates.
- visible_rect: Rect<Au>,
-}
-
-impl DisplayListOptimizer {
- /// Creates a new display list optimizer object. `visible_rect` specifies the visible rect in
- /// page coordinates.
- pub fn new(visible_rect: &Rect<f32>) -> DisplayListOptimizer {
- DisplayListOptimizer {
- visible_rect: geometry::f32_rect_to_au_rect(*visible_rect),
- }
- }
-
- /// Optimizes the given display list, returning an equivalent, but cheaper-to-paint, one.
- pub fn optimize(self, display_list: &DisplayList) -> DisplayList {
- let mut result = DisplayList::new();
- self.add_in_bounds_display_items(&mut result.background_and_borders,
- display_list.background_and_borders.iter());
- self.add_in_bounds_display_items(&mut result.block_backgrounds_and_borders,
- display_list.block_backgrounds_and_borders.iter());
- self.add_in_bounds_display_items(&mut result.floats, display_list.floats.iter());
- self.add_in_bounds_display_items(&mut result.content, display_list.content.iter());
- self.add_in_bounds_display_items(&mut result.positioned_content,
- display_list.positioned_content.iter());
- self.add_in_bounds_display_items(&mut result.outlines,
- display_list.outlines.iter());
- result
- }
-
- /// Adds display items that intersect the visible rect to `result_list`.
- fn add_in_bounds_display_items<'a, I>(&self,
- result_list: &mut LinkedList<DisplayItem>,
- display_items: I)
- where I: Iterator<Item=&'a DisplayItem> {
- for display_item in display_items {
- if !self.should_include_display_item(display_item) {
- continue;
- }
- result_list.push_back((*display_item).clone())
- }
- }
-
- 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);
- }
-
- if !self.visible_rect.intersects(&item.bounds()) {
- return false;
- }
-
- 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_thread.rs b/components/gfx/paint_thread.rs
index fdb85aff339..b427ae70ea3 100644
--- a/components/gfx/paint_thread.rs
+++ b/components/gfx/paint_thread.rs
@@ -8,15 +8,16 @@ use app_units::Au;
use azure::AzFloat;
use azure::azure_hl::{BackendType, Color, DrawTarget, SurfaceFormat};
use canvas_traits::CanvasMsg;
-use display_list::{DisplayItem, DisplayList, LayerInfo, StackingContext};
+use display_list::{DisplayItem, DisplayList, DisplayListEntry, DisplayListTraversal};
+use display_list::{LayerInfo, StackingContext, StackingContextId, StackingContextType};
use euclid::Matrix4;
use euclid::point::Point2D;
use euclid::rect::Rect;
use euclid::size::Size2D;
use font_cache_thread::FontCacheThread;
use font_context::FontContext;
-use gfx_traits::{Epoch, FrameTreeId, LayerId, LayerKind, LayerProperties};
-use gfx_traits::{PaintListener, PaintMsg as ConstellationMsg, ScrollPolicy, color};
+use gfx_traits::PaintMsg as ConstellationMsg;
+use gfx_traits::{Epoch, FrameTreeId, LayerId, LayerKind, LayerProperties, PaintListener};
use ipc_channel::ipc::IpcSender;
use layers::layers::{BufferRequest, LayerBuffer, LayerBufferSet};
use layers::platform::surface::{NativeDisplay, NativeSurface};
@@ -37,143 +38,292 @@ use util::opts;
use util::thread;
use util::thread_state;
-#[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
-pub enum PaintLayerContents {
- StackingContext(Arc<StackingContext>),
- DisplayList(Arc<DisplayList>),
-}
-
-/// Information about a hardware graphics layer that layout sends to the painting thread.
-#[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
-pub struct PaintLayer {
- /// A per-pipeline ID describing this layer that should be stable across reflows.
- pub id: LayerId,
- /// The color of the background in this layer. Used for unpainted content.
- pub background_color: Color,
- /// The content of this layer, which is either a stacking context or a display list.
- pub contents: PaintLayerContents,
- /// The layer's boundaries in the parent layer's coordinate system.
- pub bounds: Rect<Au>,
- /// The scrolling policy of this layer.
- pub scroll_policy: ScrollPolicy,
- /// The pipeline of the subpage that this layer represents, if there is one.
- pub subpage_pipeline_id: Option<PipelineId>,
+#[derive(Clone, HeapSizeOf)]
+struct PaintLayer {
+ /// The LayerProperties, which describe the layer in a way that the Compositor
+ /// can consume.
+ pub layer_properties: LayerProperties,
+
+ /// The StackingContextId of the StackingContext that is the immediate
+ /// parent of this layer. This is used to ensure applying the proper transform
+ /// when painting.
+ pub starting_stacking_context_id: StackingContextId,
+
+ /// The indices (in the DisplayList) to the first and last display item
+ /// that are the contents of this layer.
+ pub display_list_indices: Option<(usize, usize)>,
+
+ /// When painting, whether to draw the start by entering the surrounding StackingContext
+ /// or simply to draw the single item this PaintLayer contains.
+ pub single_item: bool,
+
+ /// The layer's bounds start at the overflow origin, but display items are
+ /// positioned relative to the stacking context bounds, so we need to
+ /// offset by the overflow rect (which will be in the coordinate system of
+ /// the stacking context bounds).
+ pub display_list_origin: Point2D<f32>
}
impl PaintLayer {
- /// 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 {
+ fn new_from_stacking_context(layer_info: &LayerInfo,
+ stacking_context: &StackingContext,
+ parent_origin: &Point2D<Au>,
+ transform: &Matrix4,
+ perspective: &Matrix4,
+ parent_id: Option<LayerId>)
+ -> PaintLayer {
let bounds = Rect::new(stacking_context.bounds.origin + stacking_context.overflow.origin,
stacking_context.overflow.size);
+ let layer_boundaries = Rect::new(
+ Point2D::new((parent_origin.x + bounds.min_x()).to_nearest_px() as f32,
+ (parent_origin.y + bounds.min_y()).to_nearest_px() as f32),
+ Size2D::new(bounds.size.width.to_nearest_px() as f32,
+ bounds.size.height.to_nearest_px() as f32));
+
+ let transform = transform.mul(&stacking_context.transform);
+ let perspective = perspective.mul(&stacking_context.perspective);
+ let establishes_3d_context = stacking_context.establishes_3d_context;
+ let scrolls_overflow_area = stacking_context.scrolls_overflow_area;
+
PaintLayer {
- id: layer_info.layer_id,
- background_color: background_color,
- contents: PaintLayerContents::StackingContext(stacking_context),
- bounds: bounds,
- scroll_policy: layer_info.scroll_policy,
- subpage_pipeline_id: layer_info.subpage_pipeline_id,
+ layer_properties: LayerProperties {
+ id: layer_info.layer_id,
+ parent_id: parent_id,
+ rect: layer_boundaries,
+ background_color: layer_info.background_color,
+ scroll_policy: layer_info.scroll_policy,
+ transform: transform,
+ perspective: perspective,
+ establishes_3d_context: establishes_3d_context,
+ scrolls_overflow_area: scrolls_overflow_area,
+ subpage_pipeline_id: layer_info.subpage_pipeline_id,
+ },
+ starting_stacking_context_id: stacking_context.id,
+ display_list_indices: None,
+ single_item: false,
+ display_list_origin: Point2D::new(stacking_context.overflow.origin.x.to_f32_px(),
+ stacking_context.overflow.origin.y.to_f32_px()),
}
}
- /// Creates a new `PaintLayer` with a display list.
- pub fn new_with_display_list(layer_info: LayerInfo,
- display_list: DisplayList)
- -> PaintLayer {
- let bounds = display_list.calculate_bounding_rect().expand_to_px_boundaries();
+ fn new_for_display_item(layer_info: &LayerInfo,
+ item_bounds: &Rect<Au>,
+ parent_origin: &Point2D<Au>,
+ transform: &Matrix4,
+ perspective: &Matrix4,
+ parent_id: Option<LayerId>,
+ stacking_context_id: StackingContextId,
+ item_index: usize)
+ -> PaintLayer {
+ let bounds = item_bounds.expand_to_px_boundaries();
+ let layer_boundaries = Rect::new(
+ Point2D::new((parent_origin.x + bounds.min_x()).to_nearest_px() as f32,
+ (parent_origin.y + bounds.min_y()).to_nearest_px() as f32),
+ Size2D::new(bounds.size.width.to_nearest_px() as f32,
+ bounds.size.height.to_nearest_px() as f32));
+
PaintLayer {
- id: layer_info.layer_id,
- background_color: color::transparent(),
- contents: PaintLayerContents::DisplayList(Arc::new(display_list)),
- bounds: bounds,
- scroll_policy: layer_info.scroll_policy,
- subpage_pipeline_id: layer_info.subpage_pipeline_id,
+ layer_properties: LayerProperties {
+ id: layer_info.layer_id,
+ parent_id: parent_id,
+ rect: layer_boundaries,
+ background_color: layer_info.background_color,
+ scroll_policy: layer_info.scroll_policy,
+ transform: *transform,
+ perspective: *perspective,
+ establishes_3d_context: false,
+ scrolls_overflow_area: false,
+ subpage_pipeline_id: layer_info.subpage_pipeline_id,
+ },
+ starting_stacking_context_id: stacking_context_id,
+ display_list_indices: Some((item_index, item_index)),
+ single_item: true,
+ display_list_origin: Point2D::new(bounds.origin.x.to_f32_px(),
+ bounds.origin.y.to_f32_px()),
}
}
- pub fn find_layer_with_layer_id(this: &Arc<PaintLayer>,
- layer_id: LayerId)
- -> Option<Arc<PaintLayer>> {
- if this.id == layer_id {
- return Some(this.clone());
- }
+ fn add_item(&mut self, index: usize) {
+ let indices = match self.display_list_indices {
+ Some((first, _)) => (first, index),
+ None => (index, index),
+ };
+ self.display_list_indices = Some(indices);
+ }
- match this.contents {
- PaintLayerContents::StackingContext(ref stacking_context) =>
- stacking_context.display_list.find_layer_with_layer_id(layer_id),
- PaintLayerContents::DisplayList(ref display_list) =>
- display_list.find_layer_with_layer_id(layer_id),
- }
+ fn make_companion_layer(&mut self) {
+ self.layer_properties.id = self.layer_properties.id.companion_layer_id();
+ self.display_list_indices = None;
}
+}
- fn build_layer_properties(&self,
- parent_origin: &Point2D<Au>,
- transform: &Matrix4,
- perspective: &Matrix4,
- parent_id: Option<LayerId>)
- -> LayerProperties {
- let layer_boundaries = Rect::new(
- Point2D::new((parent_origin.x + self.bounds.min_x()).to_nearest_px() as f32,
- (parent_origin.y + self.bounds.min_y()).to_nearest_px() as f32),
- Size2D::new(self.bounds.size.width.to_nearest_px() as f32,
- self.bounds.size.height.to_nearest_px() as f32));
-
- let (transform,
- perspective,
- establishes_3d_context,
- scrolls_overflow_area) = match self.contents {
- PaintLayerContents::StackingContext(ref stacking_context) => {
- (transform.mul(&stacking_context.transform),
- perspective.mul(&stacking_context.perspective),
- stacking_context.establishes_3d_context,
- stacking_context.scrolls_overflow_area)
- },
- PaintLayerContents::DisplayList(_) => {
- (*transform, *perspective, false, false)
- }
+struct LayerCreator {
+ layers: Vec<PaintLayer>,
+ layer_details_stack: Vec<PaintLayer>,
+ current_layer: Option<PaintLayer>,
+ current_entry_index: usize,
+}
+
+impl LayerCreator {
+ fn create_layers_with_display_list(display_list: &DisplayList) -> Vec<PaintLayer> {
+ let mut layer_creator = LayerCreator {
+ layers: Vec::new(),
+ layer_details_stack: Vec::new(),
+ current_layer: None,
+ current_entry_index: 0,
};
+ let mut traversal = DisplayListTraversal {
+ display_list: display_list,
+ current_item_index: 0,
+ last_item_index: display_list.list.len(),
+ };
+ layer_creator.create_layers_for_stacking_context(&display_list.root_stacking_context,
+ &mut traversal,
+ &Point2D::zero(),
+ &Matrix4::identity(),
+ &Matrix4::identity());
+ layer_creator.layers
+ }
- LayerProperties {
- id: self.id,
- parent_id: parent_id,
- rect: layer_boundaries,
- background_color: self.background_color,
- scroll_policy: self.scroll_policy,
- transform: transform,
- perspective: perspective,
- establishes_3d_context: establishes_3d_context,
- scrolls_overflow_area: scrolls_overflow_area,
- subpage_pipeline_id: self.subpage_pipeline_id,
+ fn finalize_current_layer(&mut self) {
+ if let Some(current_layer) = self.current_layer.take() {
+ self.layers.push(current_layer);
}
}
- // The origin for child layers might be somewhere other than the layer origin,
- // since layer boundaries are expanded to include overflow.
- pub fn origin_for_child_layers(&self) -> Point2D<Au> {
- match self.contents {
- PaintLayerContents::StackingContext(ref stacking_context) =>
- -stacking_context.overflow.origin,
- PaintLayerContents::DisplayList(_) => Point2D::zero(),
+ fn current_parent_layer_id(&self) -> Option<LayerId> {
+ self.layer_details_stack.last().as_ref().map(|layer|
+ layer.layer_properties.id
+ )
+ }
+
+ fn current_parent_stacking_context_id(&self) -> StackingContextId {
+ self.layer_details_stack.last().unwrap().starting_stacking_context_id
+ }
+
+ fn create_layers_for_stacking_context<'a>(&mut self,
+ stacking_context: &StackingContext,
+ traversal: &mut DisplayListTraversal<'a>,
+ parent_origin: &Point2D<Au>,
+ transform: &Matrix4,
+ perspective: &Matrix4) {
+ if let Some(ref layer_info) = stacking_context.layer_info {
+ self.finalize_current_layer();
+ let new_layer = PaintLayer::new_from_stacking_context(
+ layer_info,
+ stacking_context,
+ parent_origin,
+ transform,
+ perspective,
+ self.current_parent_layer_id());
+ self.layer_details_stack.push(new_layer.clone());
+ self.current_layer = Some(new_layer);
+
+ // When there is a new layer, the transforms and origin are handled by
+ // the compositor, so the new transform and perspective matrices are
+ // just the identity.
+ //
+ // The origin for child layers which might be somewhere other than the
+ // layer origin, since layer boundaries are expanded to include overflow.
+ self.process_stacking_context_items(stacking_context,
+ traversal,
+ &-stacking_context.overflow.origin,
+ &Matrix4::identity(),
+ &Matrix4::identity());
+ self.finalize_current_layer();
+ self.layer_details_stack.pop();
+ return;
}
+
+ if stacking_context.context_type != StackingContextType::Real {
+ self.process_stacking_context_items(stacking_context,
+ traversal,
+ parent_origin,
+ transform,
+ perspective);
+ return;
+ }
+
+ self.process_stacking_context_items(stacking_context,
+ traversal,
+ &(stacking_context.bounds.origin + *parent_origin),
+ &transform.mul(&stacking_context.transform),
+ &perspective.mul(&stacking_context.perspective));
}
- pub fn display_list_origin(&self) -> Point2D<f32> {
- // The layer's bounds start at the overflow origin, but display items are
- // positioned relative to the stacking context counds, so we need to
- // offset by the overflow rect (which will be in the coordinate system of
- // the stacking context bounds).
- match self.contents {
- PaintLayerContents::StackingContext(ref stacking_context) => {
- Point2D::new(stacking_context.overflow.origin.x.to_f32_px(),
- stacking_context.overflow.origin.y.to_f32_px())
+ fn process_stacking_context_items<'a>(&mut self,
+ stacking_context: &StackingContext,
+ traversal: &mut DisplayListTraversal<'a>,
+ parent_origin: &Point2D<Au>,
+ transform: &Matrix4,
+ perspective: &Matrix4) {
+ for kid in stacking_context.children.iter() {
+ while let Some(item) = traversal.advance(stacking_context) {
+ self.create_layers_for_item(item,
+ parent_origin,
+ transform,
+ perspective);
+ }
+ self.create_layers_for_stacking_context(kid,
+ traversal,
+ parent_origin,
+ transform,
+ perspective);
+ }
- },
- PaintLayerContents::DisplayList(_) => {
- Point2D::new(self.bounds.origin.x.to_f32_px(), self.bounds.origin.y.to_f32_px())
+ while let Some(item) = traversal.advance(stacking_context) {
+ self.create_layers_for_item(item,
+ parent_origin,
+ transform,
+ perspective);
+ }
+ }
+
+
+ fn create_layers_for_item<'a>(&mut self,
+ item: &DisplayListEntry,
+ parent_origin: &Point2D<Au>,
+ transform: &Matrix4,
+ perspective: &Matrix4) {
+ if let DisplayItem::LayeredItemClass(ref layered_item) = item.item {
+ // We need to finalize the last layer here before incrementing the entry
+ // index, otherwise this item will be placed into the parent layer.
+ self.finalize_current_layer();
+ let layer = PaintLayer::new_for_display_item(
+ &layered_item.layer_info,
+ &layered_item.item.bounds(),
+ parent_origin,
+ transform,
+ perspective,
+ self.current_parent_layer_id(),
+ self.current_parent_stacking_context_id(),
+ self.current_entry_index);
+ self.layers.push(layer);
+ self.current_entry_index += 1;
+ return;
+ }
+
+ // If we don't have a current layer, we are an item that belonged to a
+ // previous layer that was finalized by a child layer. We need to
+ // resurrect a copy of the original ancestor layer to ensure that this
+ // item is ordered on top of the child layers when painted.
+ if self.current_layer.is_none() {
+ let mut new_layer = self.layer_details_stack.pop().unwrap();
+ new_layer.make_companion_layer();
+
+ if new_layer.layer_properties.parent_id == None {
+ new_layer.layer_properties.parent_id =
+ Some(new_layer.layer_properties.id.original());
}
+
+ self.layer_details_stack.push(new_layer.clone());
+ self.current_layer = Some(new_layer);
+ }
+
+ if let Some(ref mut current_layer) = self.current_layer {
+ current_layer.add_item(self.current_entry_index);
}
+ self.current_entry_index += 1;
}
}
@@ -192,7 +342,7 @@ pub enum Msg {
#[derive(Deserialize, Serialize)]
pub enum LayoutToPaintMsg {
- PaintInit(Epoch, PaintLayer),
+ PaintInit(Epoch, Arc<DisplayList>),
CanvasLayer(LayerId, IpcSender<CanvasMsg>),
Exit(IpcSender<()>),
}
@@ -216,7 +366,10 @@ pub struct PaintThread<C> {
time_profiler_chan: time::ProfilerChan,
/// The root paint layer sent to us by the layout thread.
- root_paint_layer: Option<Arc<PaintLayer>>,
+ root_display_list: Option<Arc<DisplayList>>,
+
+ /// A map that associates LayerIds with their corresponding layers.
+ layer_map: HashMap<LayerId, Arc<PaintLayer>>,
/// Permission to send paint messages to the compositor
paint_permission: bool,
@@ -273,7 +426,8 @@ impl<C> PaintThread<C> where C: PaintListener + Send + 'static {
chrome_to_paint_port: chrome_to_paint_port,
compositor: compositor,
time_profiler_chan: time_profiler_chan,
- root_paint_layer: None,
+ root_display_list: None,
+ layer_map: HashMap::new(),
paint_permission: false,
current_epoch: None,
worker_threads: worker_threads,
@@ -312,9 +466,9 @@ impl<C> PaintThread<C> where C: PaintListener + Send + 'static {
};
match message {
- Msg::FromLayout(LayoutToPaintMsg::PaintInit(epoch, paint_layer)) => {
+ Msg::FromLayout(LayoutToPaintMsg::PaintInit(epoch, display_list)) => {
self.current_epoch = Some(epoch);
- self.root_paint_layer = Some(Arc::new(paint_layer));
+ self.root_display_list = Some(display_list);
if self.paint_permission {
self.initialize_layers();
@@ -326,7 +480,7 @@ impl<C> PaintThread<C> where C: PaintListener + Send + 'static {
self.canvas_map.insert(layer_id, canvas_renderer);
}
Msg::FromChrome(ChromeToPaintMsg::Paint(requests, frame_tree_id)) => {
- if self.paint_permission && self.root_paint_layer.is_some() {
+ if self.paint_permission && self.root_display_list.is_some() {
let mut replies = Vec::new();
for PaintRequest { buffer_requests, scale, layer_id, epoch, layer_kind }
in requests {
@@ -350,7 +504,7 @@ impl<C> PaintThread<C> where C: PaintListener + Send + 'static {
Msg::FromChrome(ChromeToPaintMsg::PaintPermissionGranted) => {
self.paint_permission = true;
- if self.root_paint_layer.is_some() {
+ if self.root_display_list.is_some() {
self.initialize_layers();
}
}
@@ -390,14 +544,15 @@ impl<C> PaintThread<C> where C: PaintListener + Send + 'static {
layer_id: LayerId,
layer_kind: LayerKind) {
time::profile(time::ProfilerCategory::Painting, None, self.time_profiler_chan.clone(), || {
+ let display_list = match self.root_display_list {
+ Some(ref display_list) => display_list.clone(),
+ None => return,
+ };
+
// Bail out if there is no appropriate layer.
- let paint_layer = if let Some(ref root_paint_layer) = self.root_paint_layer {
- match PaintLayer::find_layer_with_layer_id(root_paint_layer, layer_id) {
- Some(paint_layer) => paint_layer,
- None => return,
- }
- } else {
- return
+ let layer = match self.layer_map.get(&layer_id) {
+ Some(layer) => layer.clone(),
+ None => return,
};
// Divide up the layer into tiles and distribute them to workers via a simple round-
@@ -408,7 +563,8 @@ impl<C> PaintThread<C> where C: PaintListener + Send + 'static {
let thread_id = i % self.worker_threads.len();
self.worker_threads[thread_id].paint_tile(thread_id,
tile,
- paint_layer.clone(),
+ display_list.clone(),
+ layer.clone(),
scale,
layer_kind);
}
@@ -425,109 +581,18 @@ impl<C> PaintThread<C> where C: PaintListener + Send + 'static {
}
fn initialize_layers(&mut self) {
- let root_paint_layer = match self.root_paint_layer {
+ let root_display_list = match self.root_display_list {
None => return,
- Some(ref root_paint_layer) => root_paint_layer,
+ Some(ref root_display_list) => root_display_list,
};
-
- let mut properties = Vec::new();
- build_from_paint_layer(&mut properties,
- root_paint_layer,
- &Point2D::zero(),
- &Matrix4::identity(),
- &Matrix4::identity(),
- None);
+ let layers = LayerCreator::create_layers_with_display_list(&root_display_list);
+ let properties = layers.iter().map(|layer| layer.layer_properties.clone()).collect();
self.compositor.initialize_layers_for_pipeline(self.id,
properties,
self.current_epoch.unwrap());
-
- fn build_from_paint_layer(properties: &mut Vec<LayerProperties>,
- paint_layer: &Arc<PaintLayer>,
- parent_origin: &Point2D<Au>,
- transform: &Matrix4,
- perspective: &Matrix4,
- parent_id: Option<LayerId>) {
-
- properties.push(paint_layer.build_layer_properties(parent_origin,
- transform,
- perspective,
- parent_id));
-
- match paint_layer.contents {
- PaintLayerContents::StackingContext(ref context) => {
- // When there is a new layer, the transforms and origin are handled by the compositor,
- // so the new transform and perspective matrices are just the identity.
- continue_walking_stacking_context(properties,
- &context,
- &paint_layer.origin_for_child_layers(),
- &Matrix4::identity(),
- &Matrix4::identity(),
- Some(paint_layer.id));
- },
- PaintLayerContents::DisplayList(ref display_list) => {
- for kid in 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 display_list.layered_children.iter() {
- build_from_paint_layer(properties,
- &kid,
- &parent_origin,
- &transform,
- &perspective,
- parent_id)
- }
- },
- }
- }
-
- fn build_from_stacking_context(properties: &mut Vec<LayerProperties>,
- stacking_context: &Arc<StackingContext>,
- parent_origin: &Point2D<Au>,
- transform: &Matrix4,
- perspective: &Matrix4,
- parent_id: Option<LayerId>) {
- continue_walking_stacking_context(properties,
- stacking_context,
- &(stacking_context.bounds.origin + *parent_origin),
- &transform.mul(&stacking_context.transform),
- &perspective.mul(&stacking_context.perspective),
- parent_id);
- }
-
- fn continue_walking_stacking_context(properties: &mut Vec<LayerProperties>,
- stacking_context: &Arc<StackingContext>,
- parent_origin: &Point2D<Au>,
- transform: &Matrix4,
- perspective: &Matrix4,
- parent_id: Option<LayerId>) {
- 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() {
- build_from_paint_layer(properties,
- &kid,
- &parent_origin,
- &transform,
- &perspective,
- parent_id)
- }
+ self.layer_map.clear();
+ for layer in layers.into_iter() {
+ self.layer_map.insert(layer.layer_properties.id, Arc::new(layer));
}
}
}
@@ -570,11 +635,13 @@ impl WorkerThreadProxy {
fn paint_tile(&mut self,
thread_id: usize,
tile: BufferRequest,
+ display_list: Arc<DisplayList>,
paint_layer: Arc<PaintLayer>,
scale: f32,
layer_kind: LayerKind) {
let msg = MsgToWorkerThread::PaintTile(thread_id,
tile,
+ display_list,
paint_layer,
scale,
layer_kind);
@@ -640,9 +707,15 @@ impl WorkerThread {
loop {
match self.receiver.recv().unwrap() {
MsgToWorkerThread::Exit => break,
- MsgToWorkerThread::PaintTile(thread_id, tile, paint_layer, scale, layer_kind) => {
+ MsgToWorkerThread::PaintTile(thread_id,
+ tile,
+ display_list,
+ paint_layer,
+ scale,
+ layer_kind) => {
let buffer = self.optimize_and_paint_tile(thread_id,
tile,
+ display_list,
paint_layer,
scale,
layer_kind);
@@ -676,6 +749,7 @@ impl WorkerThread {
fn optimize_and_paint_tile(&mut self,
thread_id: usize,
mut tile: BufferRequest,
+ display_list: Arc<DisplayList>,
paint_layer: Arc<PaintLayer>,
scale: f32,
layer_kind: LayerKind)
@@ -700,7 +774,7 @@ impl WorkerThread {
// Apply the translation to paint the tile we want.
let matrix = Matrix4::identity();
let matrix = matrix.scale(scale as AzFloat, scale as AzFloat, 1.0);
- let tile_bounds = tile.page_rect.translate(&paint_layer.display_list_origin());
+ let tile_bounds = tile.page_rect.translate(&paint_layer.display_list_origin);
let matrix = matrix.translate(-tile_bounds.origin.x as AzFloat,
-tile_bounds.origin.y as AzFloat,
0.0);
@@ -711,26 +785,22 @@ impl WorkerThread {
// Draw the display list.
time::profile(time::ProfilerCategory::PaintingPerTile,
None,
- self.time_profiler_sender.clone(),
- || {
- match paint_layer.contents {
- PaintLayerContents::StackingContext(ref stacking_context) => {
- stacking_context.optimize_and_draw_into_context(&mut paint_context,
- &matrix,
- None);
- }
- PaintLayerContents::DisplayList(ref display_list) => {
- paint_context.remove_transient_clip_if_applicable();
- let draw_target = paint_context.draw_target.clone();
- display_list.draw_into_context(&draw_target,
- &mut paint_context,
- &matrix,
- None);
- }
- }
-
- paint_context.draw_target.flush();
- });
+ self.time_profiler_sender.clone(), || {
+ if let Some((start, end)) = paint_layer.display_list_indices {
+ if paint_layer.single_item {
+ display_list.draw_item_at_index_into_context(
+ &mut paint_context, &matrix, start);
+ } else {
+ display_list.draw_into_context(
+ &mut paint_context,
+ &matrix,
+ paint_layer.starting_stacking_context_id,
+ start,
+ end);
+ }
+ }
+ paint_context.draw_target.flush();
+ });
if opts::get().show_debug_parallel_paint {
// Overlay a transparent solid color to identify the thread that
@@ -791,7 +861,7 @@ impl WorkerThread {
enum MsgToWorkerThread {
Exit,
- PaintTile(usize, BufferRequest, Arc<PaintLayer>, f32, LayerKind),
+ PaintTile(usize, BufferRequest, Arc<DisplayList>, Arc<PaintLayer>, f32, LayerKind),
}
enum MsgFromWorkerThread {
diff --git a/components/gfx_traits/lib.rs b/components/gfx_traits/lib.rs
index 84e74038e40..c3cda7c1bb9 100644
--- a/components/gfx_traits/lib.rs
+++ b/components/gfx_traits/lib.rs
@@ -98,11 +98,16 @@ impl LayerId {
let LayerId(layer_type, id, companion) = *self;
LayerId(layer_type, id, companion + 1)
}
+
+ pub fn original(&self) -> LayerId {
+ let LayerId(layer_type, id, _) = *self;
+ LayerId(layer_type, id, 0)
+ }
}
/// All layer-specific information that the painting task sends to the compositor other than the
/// buffer contents of the layer itself.
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, HeapSizeOf)]
pub struct LayerProperties {
/// An opaque ID. This is usually the address of the flow and index of the box within it.
pub id: LayerId,
diff --git a/components/layout/block.rs b/components/layout/block.rs
index 05ffa1838f0..a538a768efd 100644
--- a/components/layout/block.rs
+++ b/components/layout/block.rs
@@ -29,8 +29,8 @@
use app_units::{Au, MAX_AU};
use context::LayoutContext;
-use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode};
-use display_list_builder::{FragmentDisplayListBuilding};
+use display_list_builder::BlockFlowDisplayListBuilding;
+use display_list_builder::{BorderPaintingMode, DisplayListBuildState, FragmentDisplayListBuilding};
use euclid::{Point2D, Rect, Size2D};
use floats::{ClearType, FloatKind, Floats, PlacementInfo};
use flow::{BLOCK_POSITION_IS_STATIC};
@@ -45,7 +45,7 @@ use flow_list::FlowList;
use flow_ref::FlowRef;
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, HAS_LAYER, Overflow};
use fragment::{SpecificFragmentInfo};
-use gfx::display_list::{ClippingRegion, DisplayList};
+use gfx::display_list::{ClippingRegion, StackingContext, StackingContextId};
use gfx_traits::LayerId;
use incremental::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT};
use layout_debug;
@@ -1622,6 +1622,29 @@ impl BlockFlow {
}
}
+ pub fn establishes_pseudo_stacking_context(&self) -> bool {
+ if self.fragment.establishes_stacking_context() {
+ return false;
+ }
+
+ self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) ||
+ self.fragment.style.get_box().position != position::T::static_ ||
+ self.base.flags.is_float()
+ }
+
+ pub fn has_scrolling_overflow(&self) -> bool {
+ if !self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) {
+ return false;
+ }
+
+ match (self.fragment.style().get_box().overflow_x,
+ self.fragment.style().get_box().overflow_y.0) {
+ (overflow_x::T::auto, _) | (overflow_x::T::scroll, _) |
+ (_, overflow_x::T::auto) | (_, overflow_x::T::scroll) => true,
+ (_, _) => false,
+ }
+ }
+
pub fn compute_inline_sizes(&mut self, layout_context: &LayoutContext) {
if !self.base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) {
return
@@ -2084,10 +2107,15 @@ impl Flow for BlockFlow {
}
}
- fn build_display_list(&mut self, layout_context: &LayoutContext) {
- self.build_display_list_for_block(box DisplayList::new(),
- layout_context,
- BorderPaintingMode::Separate);
+ fn collect_stacking_contexts(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>)
+ -> StackingContextId {
+ self.collect_stacking_contexts_for_block(parent_id, contexts)
+ }
+
+ fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
+ self.build_display_list_for_block(state, BorderPaintingMode::Separate);
self.fragment.restyle_damage.remove(REPAINT);
if opts::get().validate_display_list_geometry {
self.base.validate_display_list_geometry();
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index 8d5e5c48ed0..04beaca2064 100644
--- a/components/layout/display_list_builder.rs
+++ b/components/layout/display_list_builder.rs
@@ -24,11 +24,12 @@ use fragment::{CoordinateSystem, Fragment, HAS_LAYER, ImageFragmentInfo, Scanned
use fragment::{SpecificFragmentInfo};
use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDisplayItem};
use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion};
-use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayList, DisplayListSection};
+use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayListSection};
use gfx::display_list::{GradientDisplayItem};
use gfx::display_list::{GradientStop, IframeDisplayItem, ImageDisplayItem, WebGLDisplayItem, LayeredItem, LayerInfo};
use gfx::display_list::{LineDisplayItem, OpaqueNode, SolidColorDisplayItem};
-use gfx::display_list::{StackingContext, TextDisplayItem, TextOrientation};
+use gfx::display_list::{StackingContext, StackingContextId, StackingContextType};
+use gfx::display_list::{TextDisplayItem, TextOrientation, DisplayListEntry};
use gfx::paint_thread::THREAD_TINT_COLORS;
use gfx::text::glyph::CharIndex;
use gfx_traits::{color, ScrollPolicy};
@@ -59,6 +60,53 @@ use table_cell::CollapsedBordersForCell;
use url::Url;
use util::opts;
+pub struct DisplayListBuildState<'a> {
+ pub layout_context: &'a LayoutContext<'a>,
+ pub items: Vec<DisplayListEntry>,
+ pub stacking_context_id_stack: Vec<StackingContextId>,
+}
+
+impl<'a> DisplayListBuildState<'a> {
+ pub fn new(layout_context: &'a LayoutContext,
+ stacking_context_id: StackingContextId)
+ -> DisplayListBuildState<'a> {
+ DisplayListBuildState {
+ layout_context: layout_context,
+ items: Vec::new(),
+ stacking_context_id_stack: vec!(stacking_context_id),
+ }
+ }
+
+ fn add_display_item(&mut self, display_item: DisplayItem, section: DisplayListSection) {
+ let stacking_context_id = self.stacking_context_id();
+ self.items.push(
+ DisplayListEntry {
+ stacking_context_id: stacking_context_id,
+ section: section,
+ item: display_item
+ });
+ }
+
+ fn append_from(&mut self, other_list: &mut Option<Vec<DisplayListEntry>>) {
+ if let Some(mut other) = other_list.take() {
+ self.items.append(&mut other);
+ }
+ }
+
+ fn stacking_context_id(&self) -> StackingContextId {
+ self.stacking_context_id_stack.last().unwrap().clone()
+ }
+
+ fn push_stacking_context_id(&mut self, stacking_context_id: StackingContextId) {
+ self.stacking_context_id_stack.push(stacking_context_id);
+ }
+
+ fn pop_stacking_context_id(&mut self) {
+ self.stacking_context_id_stack.pop();
+ assert!(!self.stacking_context_id_stack.is_empty());
+ }
+}
+
/// The logical width of an insertion point: at the moment, a one-pixel-wide line.
const INSERTION_POINT_LOGICAL_WIDTH: Au = Au(1 * AU_PER_PX);
@@ -83,9 +131,8 @@ pub trait FragmentDisplayListBuilding {
/// Adds the display items necessary to paint the background of this fragment to the display
/// list if necessary.
fn build_display_list_for_background_if_applicable(&self,
+ state: &mut DisplayListBuildState,
style: &ComputedValues,
- display_list: &mut DisplayList,
- layout_context: &LayoutContext,
display_list_section: DisplayListSection,
absolute_bounds: &Rect<Au>,
clip: &ClippingRegion);
@@ -101,9 +148,8 @@ pub trait FragmentDisplayListBuilding {
/// Adds the display items necessary to paint the background image of this fragment to the
/// appropriate section of the display list.
fn build_display_list_for_background_image(&self,
+ state: &mut DisplayListBuildState,
style: &ComputedValues,
- display_list: &mut DisplayList,
- layout_context: &LayoutContext,
display_list_section: DisplayListSection,
absolute_bounds: &Rect<Au>,
clip: &ClippingRegion,
@@ -112,7 +158,7 @@ pub trait FragmentDisplayListBuilding {
/// Adds the display items necessary to paint the background linear gradient of this fragment
/// to the appropriate section of the display list.
fn build_display_list_for_background_linear_gradient(&self,
- display_list: &mut DisplayList,
+ state: &mut DisplayListBuildState,
display_list_section: DisplayListSection,
absolute_bounds: &Rect<Au>,
clip: &ClippingRegion,
@@ -123,9 +169,9 @@ pub trait FragmentDisplayListBuilding {
/// necessary.
fn build_display_list_for_borders_if_applicable(
&self,
+ state: &mut DisplayListBuildState,
style: &ComputedValues,
border_painting_mode: BorderPaintingMode,
- display_list: &mut DisplayList,
bounds: &Rect<Au>,
display_list_section: DisplayListSection,
clip: &ClippingRegion);
@@ -133,25 +179,24 @@ pub trait FragmentDisplayListBuilding {
/// Adds the display items necessary to paint the outline of this fragment to the display list
/// if necessary.
fn build_display_list_for_outline_if_applicable(&self,
+ state: &mut DisplayListBuildState,
style: &ComputedValues,
- display_list: &mut DisplayList,
bounds: &Rect<Au>,
clip: &ClippingRegion);
/// Adds the display items necessary to paint the box shadow of this fragment to the display
/// list if necessary.
fn build_display_list_for_box_shadow_if_applicable(&self,
+ state: &mut DisplayListBuildState,
style: &ComputedValues,
- list: &mut DisplayList,
- layout_context: &LayoutContext,
display_list_section: DisplayListSection,
absolute_bounds: &Rect<Au>,
clip: &ClippingRegion);
/// Adds display items necessary to draw debug boxes around a scanned text fragment.
fn build_debug_borders_around_text_fragments(&self,
+ state: &mut DisplayListBuildState,
style: &ComputedValues,
- display_list: &mut DisplayList,
stacking_relative_border_box: &Rect<Au>,
stacking_relative_content_box: &Rect<Au>,
text_fragment: &ScannedTextFragmentInfo,
@@ -159,7 +204,7 @@ pub trait FragmentDisplayListBuilding {
/// Adds display items necessary to draw debug boxes around this fragment.
fn build_debug_borders_around_fragment(&self,
- display_list: &mut DisplayList,
+ state: &mut DisplayListBuildState,
stacking_relative_border_box: &Rect<Au>,
clip: &ClippingRegion);
@@ -167,8 +212,8 @@ pub trait FragmentDisplayListBuilding {
///
/// Arguments:
///
- /// * `display_list`: The display list to add display items to.
- /// * `layout_context`: The layout context.
+ /// * `state`: The display building state, including the display list currently
+ /// under construction and other metadata useful for constructing it.
/// * `dirty`: The dirty rectangle in the coordinate system of the owning flow.
/// * `stacking_relative_flow_origin`: Position of the origin of the owning flow with respect
/// to its nearest ancestor stacking context.
@@ -178,8 +223,7 @@ pub trait FragmentDisplayListBuilding {
/// * `stacking_relative_display_port`: The position and size of the display port with respect
/// to the nearest ancestor stacking context.
fn build_display_list(&mut self,
- display_list: &mut DisplayList,
- layout_context: &LayoutContext,
+ state: &mut DisplayListBuildState,
stacking_relative_flow_origin: &Point2D<Au>,
relative_containing_block_size: &LogicalSize<Au>,
relative_containing_block_mode: WritingMode,
@@ -205,7 +249,7 @@ pub trait FragmentDisplayListBuilding {
/// Builds the display items necessary to paint the selection and/or caret for this fragment,
/// if any.
fn build_display_items_for_selection_if_necessary(&self,
- display_list: &mut DisplayList,
+ state: &mut DisplayListBuildState,
stacking_relative_border_box: &Rect<Au>,
display_list_section: DisplayListSection,
clip: &ClippingRegion);
@@ -215,7 +259,7 @@ pub trait FragmentDisplayListBuilding {
///
/// `shadow_blur_radius` will be `Some` if this is a shadow, even if the blur radius is zero.
fn build_display_list_for_text_fragment(&self,
- display_list: &mut DisplayList,
+ state: &mut DisplayListBuildState,
text_fragment: &ScannedTextFragmentInfo,
text_color: RGBA,
stacking_relative_content_box: &Rect<Au>,
@@ -225,7 +269,7 @@ pub trait FragmentDisplayListBuilding {
/// Creates the display item for a text decoration: underline, overline, or line-through.
fn build_display_list_for_text_decoration(&self,
- display_list: &mut DisplayList,
+ state: &mut DisplayListBuildState,
color: &RGBA,
stacking_relative_box: &LogicalRect<Au>,
clip: &ClippingRegion,
@@ -233,18 +277,17 @@ pub trait FragmentDisplayListBuilding {
/// A helper method that `build_display_list` calls to create per-fragment-type display items.
fn build_fragment_type_specific_display_items(&mut self,
- display_list: &mut DisplayList,
- layout_context: &LayoutContext,
+ state: &mut DisplayListBuildState,
stacking_relative_border_box: &Rect<Au>,
clip: &ClippingRegion);
/// Creates a stacking context for associated fragment.
fn create_stacking_context(&self,
+ id: StackingContextId,
base_flow: &BaseFlow,
- display_list: Box<DisplayList>,
scroll_policy: ScrollPolicy,
mode: StackingContextCreationMode)
- -> Arc<StackingContext>;
+ -> StackingContext;
}
fn handle_overlapping_radii(size: &Size2D<Au>, radii: &BorderRadii<Au>) -> BorderRadii<Au> {
@@ -291,9 +334,8 @@ fn build_border_radius(abs_bounds: &Rect<Au>, border_style: &Border) -> BorderRa
impl FragmentDisplayListBuilding for Fragment {
fn build_display_list_for_background_if_applicable(&self,
+ state: &mut DisplayListBuildState,
style: &ComputedValues,
- display_list: &mut DisplayList,
- layout_context: &LayoutContext,
display_list_section: DisplayListSection,
absolute_bounds: &Rect<Au>,
clip: &ClippingRegion) {
@@ -332,14 +374,15 @@ impl FragmentDisplayListBuilding for Fragment {
}
}
- display_list.add_to_section(DisplayItem::SolidColorClass(box SolidColorDisplayItem {
- base: BaseDisplayItem::new(&bounds,
- DisplayItemMetadata::new(self.node,
- style,
- Cursor::DefaultCursor),
- &clip),
- color: background_color.to_gfx_color(),
- }), display_list_section);
+ state.add_display_item(
+ DisplayItem::SolidColorClass(box SolidColorDisplayItem {
+ base: BaseDisplayItem::new(&bounds,
+ DisplayItemMetadata::new(self.node,
+ style,
+ Cursor::DefaultCursor),
+ &clip),
+ color: background_color.to_gfx_color(),
+ }), display_list_section);
// The background image is painted on top of the background color.
// Implements background image, per spec:
@@ -348,21 +391,20 @@ impl FragmentDisplayListBuilding for Fragment {
match background.background_image.0 {
None => {}
Some(computed::Image::LinearGradient(ref gradient)) => {
- self.build_display_list_for_background_linear_gradient(display_list,
+ self.build_display_list_for_background_linear_gradient(state,
display_list_section,
&bounds,
&clip,
gradient,
- style)
+ style);
}
Some(computed::Image::Url(ref image_url)) => {
- self.build_display_list_for_background_image(style,
- display_list,
- layout_context,
+ self.build_display_list_for_background_image(state,
+ style,
display_list_section,
&bounds,
&clip,
- image_url)
+ image_url);
}
}
}
@@ -421,15 +463,15 @@ impl FragmentDisplayListBuilding for Fragment {
}
fn build_display_list_for_background_image(&self,
+ state: &mut DisplayListBuildState,
style: &ComputedValues,
- display_list: &mut DisplayList,
- layout_context: &LayoutContext,
display_list_section: DisplayListSection,
absolute_bounds: &Rect<Au>,
clip: &ClippingRegion,
image_url: &Url) {
let background = style.get_background();
- let image = layout_context.get_or_request_image(image_url.clone(), UsePlaceholder::No);
+ let image =
+ state.layout_context.get_or_request_image(image_url.clone(), UsePlaceholder::No);
if let Some(image) = image {
debug!("(building display list) building background image");
@@ -519,7 +561,7 @@ impl FragmentDisplayListBuilding for Fragment {
};
// Create the image display item.
- display_list.add_to_section(DisplayItem::ImageClass(box ImageDisplayItem {
+ state.add_display_item(DisplayItem::ImageClass(box ImageDisplayItem {
base: BaseDisplayItem::new(&bounds,
DisplayItemMetadata::new(self.node,
style,
@@ -533,7 +575,7 @@ impl FragmentDisplayListBuilding for Fragment {
}
fn build_display_list_for_background_linear_gradient(&self,
- display_list: &mut DisplayList,
+ state: &mut DisplayListBuildState,
display_list_section: DisplayListSection,
absolute_bounds: &Rect<Au>,
clip: &ClippingRegion,
@@ -648,13 +690,12 @@ impl FragmentDisplayListBuilding for Fragment {
stops: stops,
});
- display_list.add_to_section(gradient_display_item, display_list_section)
+ state.add_display_item(gradient_display_item, display_list_section);
}
fn build_display_list_for_box_shadow_if_applicable(&self,
+ state: &mut DisplayListBuildState,
style: &ComputedValues,
- list: &mut DisplayList,
- _layout_context: &LayoutContext,
display_list_section: DisplayListSection,
absolute_bounds: &Rect<Au>,
clip: &ClippingRegion) {
@@ -667,7 +708,7 @@ impl FragmentDisplayListBuilding for Fragment {
box_shadow.spread_radius);
// TODO(pcwalton): Multiple border radii; elliptical border radii.
- list.add_to_section(DisplayItem::BoxShadowClass(box BoxShadowDisplayItem {
+ state.add_display_item(DisplayItem::BoxShadowClass(box BoxShadowDisplayItem {
base: BaseDisplayItem::new(&bounds,
DisplayItemMetadata::new(self.node,
style,
@@ -692,9 +733,9 @@ impl FragmentDisplayListBuilding for Fragment {
fn build_display_list_for_borders_if_applicable(
&self,
+ state: &mut DisplayListBuildState,
style: &ComputedValues,
border_painting_mode: BorderPaintingMode,
- display_list: &mut DisplayList,
bounds: &Rect<Au>,
display_list_section: DisplayListSection,
clip: &ClippingRegion) {
@@ -738,7 +779,7 @@ impl FragmentDisplayListBuilding for Fragment {
}
// Append the border to the display list.
- display_list.add_to_section(DisplayItem::BorderClass(box BorderDisplayItem {
+ state.add_display_item(DisplayItem::BorderClass(box BorderDisplayItem {
base: BaseDisplayItem::new(&bounds,
DisplayItemMetadata::new(self.node,
style,
@@ -755,8 +796,8 @@ impl FragmentDisplayListBuilding for Fragment {
}
fn build_display_list_for_outline_if_applicable(&self,
+ state: &mut DisplayListBuildState,
style: &ComputedValues,
- display_list: &mut DisplayList,
bounds: &Rect<Au>,
clip: &ClippingRegion) {
let width = style.get_outline().outline_width;
@@ -780,7 +821,7 @@ impl FragmentDisplayListBuilding for Fragment {
// Append the outline to the display list.
let color = style.resolve_color(style.get_outline().outline_color).to_gfx_color();
- display_list.outlines.push_back(DisplayItem::BorderClass(box BorderDisplayItem {
+ state.add_display_item(DisplayItem::BorderClass(box BorderDisplayItem {
base: BaseDisplayItem::new(&bounds,
DisplayItemMetadata::new(self.node,
style,
@@ -790,12 +831,12 @@ impl FragmentDisplayListBuilding for Fragment {
color: SideOffsets2D::new_all_same(color),
style: SideOffsets2D::new_all_same(outline_style),
radius: Default::default(),
- }))
+ }), DisplayListSection::Outlines);
}
fn build_debug_borders_around_text_fragments(&self,
+ state: &mut DisplayListBuildState,
style: &ComputedValues,
- display_list: &mut DisplayList,
stacking_relative_border_box: &Rect<Au>,
stacking_relative_content_box: &Rect<Au>,
text_fragment: &ScannedTextFragmentInfo,
@@ -804,7 +845,7 @@ impl FragmentDisplayListBuilding for Fragment {
let container_size = Size2D::zero();
// Compute the text fragment bounds and draw a border surrounding them.
- display_list.content.push_back(DisplayItem::BorderClass(box BorderDisplayItem {
+ state.add_display_item(DisplayItem::BorderClass(box BorderDisplayItem {
base: BaseDisplayItem::new(stacking_relative_border_box,
DisplayItemMetadata::new(self.node,
style,
@@ -814,7 +855,7 @@ impl FragmentDisplayListBuilding for Fragment {
color: SideOffsets2D::new_all_same(color::rgb(0, 0, 200)),
style: SideOffsets2D::new_all_same(border_style::T::solid),
radius: Default::default(),
- }));
+ }), DisplayListSection::Content);
// Draw a rectangle representing the baselines.
let mut baseline = LogicalRect::from_physical(self.style.writing_mode,
@@ -824,7 +865,7 @@ impl FragmentDisplayListBuilding for Fragment {
baseline.size.block = Au(0);
let baseline = baseline.to_physical(self.style.writing_mode, container_size);
- let line_display_item = box LineDisplayItem {
+ state.add_display_item(DisplayItem::LineClass(box LineDisplayItem {
base: BaseDisplayItem::new(&baseline,
DisplayItemMetadata::new(self.node,
style,
@@ -832,16 +873,15 @@ impl FragmentDisplayListBuilding for Fragment {
clip),
color: color::rgb(0, 200, 0),
style: border_style::T::dashed,
- };
- display_list.content.push_back(DisplayItem::LineClass(line_display_item));
+ }), DisplayListSection::Content);
}
fn build_debug_borders_around_fragment(&self,
- display_list: &mut DisplayList,
+ state: &mut DisplayListBuildState,
stacking_relative_border_box: &Rect<Au>,
clip: &ClippingRegion) {
// This prints a debug border around the border of this fragment.
- display_list.content.push_back(DisplayItem::BorderClass(box BorderDisplayItem {
+ state.add_display_item(DisplayItem::BorderClass(box BorderDisplayItem {
base: BaseDisplayItem::new(stacking_relative_border_box,
DisplayItemMetadata::new(self.node,
&*self.style,
@@ -851,7 +891,7 @@ impl FragmentDisplayListBuilding for Fragment {
color: SideOffsets2D::new_all_same(color::rgb(0, 0, 200)),
style: SideOffsets2D::new_all_same(border_style::T::solid),
radius: Default::default(),
- }));
+ }), DisplayListSection::Content);
}
fn calculate_style_specified_clip(&self,
@@ -875,7 +915,7 @@ impl FragmentDisplayListBuilding for Fragment {
}
fn build_display_items_for_selection_if_necessary(&self,
- display_list: &mut DisplayList,
+ state: &mut DisplayListBuildState,
stacking_relative_border_box: &Rect<Au>,
display_list_section: DisplayListSection,
clip: &ClippingRegion) {
@@ -910,7 +950,7 @@ impl FragmentDisplayListBuilding for Fragment {
cursor = Cursor::VerticalTextCursor;
};
- display_list.add_to_section(DisplayItem::SolidColorClass(box SolidColorDisplayItem {
+ state.add_display_item(DisplayItem::SolidColorClass(box SolidColorDisplayItem {
base: BaseDisplayItem::new(&insertion_point_bounds,
DisplayItemMetadata::new(self.node, &*self.style, cursor),
&clip),
@@ -919,8 +959,7 @@ impl FragmentDisplayListBuilding for Fragment {
}
fn build_display_list(&mut self,
- display_list: &mut DisplayList,
- layout_context: &LayoutContext,
+ state: &mut DisplayListBuildState,
stacking_relative_flow_origin: &Point2D<Au>,
relative_containing_block_size: &LogicalSize<Au>,
relative_containing_block_mode: WritingMode,
@@ -969,16 +1008,14 @@ impl FragmentDisplayListBuilding for Fragment {
if let Some(ref inline_context) = self.inline_context {
for node in inline_context.nodes.iter().rev() {
self.build_display_list_for_background_if_applicable(
+ state,
&*node.style,
- display_list,
- layout_context,
display_list_section,
&stacking_relative_border_box,
&clip);
self.build_display_list_for_box_shadow_if_applicable(
+ state,
&*node.style,
- display_list,
- layout_context,
display_list_section,
&stacking_relative_border_box,
&clip);
@@ -989,69 +1026,65 @@ impl FragmentDisplayListBuilding for Fragment {
node.flags.contains(FIRST_FRAGMENT_OF_ELEMENT),
node.flags.contains(LAST_FRAGMENT_OF_ELEMENT));
self.build_display_list_for_borders_if_applicable(
+ state,
&*style,
border_painting_mode,
- display_list,
&stacking_relative_border_box,
display_list_section,
&clip);
self.build_display_list_for_outline_if_applicable(
+ state,
&*node.style,
- display_list,
&stacking_relative_border_box,
&clip);
}
}
if !self.is_scanned_text_fragment() {
- self.build_display_list_for_background_if_applicable(&*self.style,
- display_list,
- layout_context,
+ self.build_display_list_for_background_if_applicable(state,
+ &*self.style,
display_list_section,
&stacking_relative_border_box,
&clip);
- self.build_display_list_for_box_shadow_if_applicable(&*self.style,
- display_list,
- layout_context,
+ self.build_display_list_for_box_shadow_if_applicable(state,
+ &*self.style,
display_list_section,
&stacking_relative_border_box,
&clip);
- self.build_display_list_for_borders_if_applicable(&*self.style,
+ self.build_display_list_for_borders_if_applicable(state,
+ &*self.style,
border_painting_mode,
- display_list,
&stacking_relative_border_box,
display_list_section,
&clip);
- self.build_display_list_for_outline_if_applicable(&*self.style,
- display_list,
+ self.build_display_list_for_outline_if_applicable(state,
+ &*self.style,
&stacking_relative_border_box,
&clip);
}
// Paint the selection point if necessary.
- self.build_display_items_for_selection_if_necessary(display_list,
+ self.build_display_items_for_selection_if_necessary(state,
&stacking_relative_border_box,
display_list_section,
&clip);
}
// Create special per-fragment-type display items.
- self.build_fragment_type_specific_display_items(display_list,
- layout_context,
+ self.build_fragment_type_specific_display_items(state,
&stacking_relative_border_box,
&clip);
if opts::get().show_debug_fragment_borders {
- self.build_debug_borders_around_fragment(display_list,
+ self.build_debug_borders_around_fragment(state,
&stacking_relative_border_box,
- &clip)
+ &clip);
}
}
fn build_fragment_type_specific_display_items(&mut self,
- display_list: &mut DisplayList,
- layout_context: &LayoutContext,
+ state: &mut DisplayListBuildState,
stacking_relative_border_box: &Rect<Au>,
clip: &ClippingRegion) {
// Compute the context box position relative to the parent stacking context.
@@ -1068,7 +1101,7 @@ impl FragmentDisplayListBuilding for Fragment {
for text_shadow in self.style.get_effects().text_shadow.0.iter().rev() {
let offset = &Point2D::new(text_shadow.offset_x, text_shadow.offset_y);
let color = self.style().resolve_color(text_shadow.color);
- self.build_display_list_for_text_fragment(display_list,
+ self.build_display_list_for_text_fragment(state,
&**text_fragment,
color,
&stacking_relative_content_box,
@@ -1078,7 +1111,7 @@ impl FragmentDisplayListBuilding for Fragment {
}
// Create the main text display item.
- self.build_display_list_for_text_fragment(display_list,
+ self.build_display_list_for_text_fragment(state,
&**text_fragment,
text_color,
&stacking_relative_content_box,
@@ -1087,12 +1120,12 @@ impl FragmentDisplayListBuilding for Fragment {
clip);
if opts::get().show_debug_fragment_borders {
- self.build_debug_borders_around_text_fragments(self.style(),
- display_list,
+ self.build_debug_borders_around_text_fragments(state,
+ self.style(),
stacking_relative_border_box,
&stacking_relative_content_box,
&**text_fragment,
- clip)
+ clip);
}
}
SpecificFragmentInfo::Generic |
@@ -1107,7 +1140,7 @@ impl FragmentDisplayListBuilding for Fragment {
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
SpecificFragmentInfo::InlineAbsolute(_) => {
if opts::get().show_debug_fragment_borders {
- self.build_debug_borders_around_fragment(display_list,
+ self.build_debug_borders_around_fragment(state,
stacking_relative_border_box,
clip);
}
@@ -1115,36 +1148,38 @@ impl FragmentDisplayListBuilding for Fragment {
SpecificFragmentInfo::Iframe(ref fragment_info) => {
if !stacking_relative_content_box.is_empty() {
if opts::get().use_webrender {
- display_list.content.push_back(DisplayItem::IframeClass(box IframeDisplayItem {
- base: BaseDisplayItem::new(&stacking_relative_content_box,
- DisplayItemMetadata::new(self.node,
- &*self.style,
- Cursor::DefaultCursor),
- clip),
+ state.add_display_item(DisplayItem::IframeClass(box IframeDisplayItem {
+ base: BaseDisplayItem::new(
+ &stacking_relative_content_box,
+ DisplayItemMetadata::new(self.node,
+ &*self.style,
+ Cursor::DefaultCursor),
+ clip),
iframe: fragment_info.pipeline_id,
- }));
+ }), DisplayListSection::Content);
} else {
let layer_id = self.layer_id();
- display_list.content.push_back(DisplayItem::LayeredItemClass(box LayeredItem {
+ state.add_display_item(DisplayItem::LayeredItemClass(box LayeredItem {
item: DisplayItem::NoopClass(
- box BaseDisplayItem::new(&stacking_relative_content_box,
- DisplayItemMetadata::new(self.node,
- &*self.style,
- Cursor::DefaultCursor),
- clip)),
- layer_id: layer_id
- }));
-
- display_list.layer_info.push_back(LayerInfo::new(layer_id,
- ScrollPolicy::Scrollable,
- Some(fragment_info.pipeline_id)));
+ box BaseDisplayItem::new(
+ &stacking_relative_content_box,
+ DisplayItemMetadata::new(self.node,
+ &*self.style,
+ Cursor::DefaultCursor),
+ clip)),
+ layer_id: layer_id,
+ layer_info: LayerInfo::new(layer_id,
+ ScrollPolicy::Scrollable,
+ Some(fragment_info.pipeline_id),
+ color::transparent()),
+ }), DisplayListSection::Content);
}
}
}
SpecificFragmentInfo::Image(ref mut image_fragment) => {
// Place the image into the display list.
if let Some(ref image) = image_fragment.image {
- display_list.content.push_back(DisplayItem::ImageClass(box ImageDisplayItem {
+ state.add_display_item(DisplayItem::ImageClass(box ImageDisplayItem {
base: BaseDisplayItem::new(&stacking_relative_content_box,
DisplayItemMetadata::new(self.node,
&*self.style,
@@ -1153,7 +1188,7 @@ impl FragmentDisplayListBuilding for Fragment {
image: image.clone(),
stretch_size: stacking_relative_content_box.size,
image_rendering: self.style.get_effects().image_rendering.clone(),
- }));
+ }), DisplayListSection::Content);
}
}
SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => {
@@ -1171,8 +1206,8 @@ impl FragmentDisplayListBuilding for Fragment {
FromLayoutMsg::SendData(sender))).unwrap();
let data = receiver.recv().unwrap();
- // Propagate the layer and the renderer to the paint thread.
- layout_context.shared.canvas_layers_sender.lock().unwrap().send(
+ // Propagate the layer and the renderer to the paint task.
+ state.layout_context.shared.canvas_layers_sender.lock().unwrap().send(
(layer_id, (*ipc_renderer).clone())).unwrap();
data
@@ -1215,15 +1250,16 @@ impl FragmentDisplayListBuilding for Fragment {
};
if opts::get().use_webrender {
- display_list.content.push_back(display_item);
+ state.add_display_item(display_item, DisplayListSection::Content);
} else {
- display_list.content.push_back(DisplayItem::LayeredItemClass(box LayeredItem {
+ state.add_display_item(DisplayItem::LayeredItemClass(box LayeredItem {
item: display_item,
- layer_id: layer_id
- }));
-
- display_list.layer_info.push_back(
- LayerInfo::new(layer_id, ScrollPolicy::Scrollable, None));
+ layer_id: layer_id,
+ layer_info: LayerInfo::new(layer_id,
+ ScrollPolicy::Scrollable,
+ None,
+ color::transparent()),
+ }), DisplayListSection::Content);
}
}
}
@@ -1237,14 +1273,16 @@ impl FragmentDisplayListBuilding for Fragment {
}
fn create_stacking_context(&self,
+ id: StackingContextId,
base_flow: &BaseFlow,
- display_list: Box<DisplayList>,
scroll_policy: ScrollPolicy,
mode: StackingContextCreationMode)
- -> Arc<StackingContext> {
+ -> StackingContext {
let border_box = match mode {
- StackingContextCreationMode::Normal |
- StackingContextCreationMode::OuterScrollWrapper => {
+ StackingContextCreationMode::InnerScrollWrapper => {
+ Rect::new(Point2D::zero(), base_flow.overflow.scroll.size)
+ }
+ _ => {
self.stacking_relative_border_box(&base_flow.stacking_relative_position,
&base_flow.early_absolute_position_info
.relative_containing_block_size,
@@ -1252,12 +1290,13 @@ impl FragmentDisplayListBuilding for Fragment {
.relative_containing_block_mode,
CoordinateSystem::Parent)
}
- StackingContextCreationMode::InnerScrollWrapper => {
- Rect::new(Point2D::zero(), base_flow.overflow.scroll.size)
- }
};
let overflow = match mode {
- StackingContextCreationMode::Normal => {
+ StackingContextCreationMode::InnerScrollWrapper |
+ StackingContextCreationMode::OuterScrollWrapper => {
+ Rect::new(Point2D::zero(), border_box.size)
+ }
+ _ => {
// First, compute the offset of our border box (including relative positioning)
// from our flow origin, since that is what `BaseFlow::overflow` is relative to.
let border_box_offset =
@@ -1265,10 +1304,6 @@ impl FragmentDisplayListBuilding for Fragment {
// Then, using that, compute our overflow region relative to our border box.
base_flow.overflow.paint.translate(&-border_box_offset)
}
- StackingContextCreationMode::InnerScrollWrapper |
- StackingContextCreationMode::OuterScrollWrapper => {
- Rect::new(Point2D::zero(), border_box.size)
- }
};
let mut transform = Matrix4::identity();
@@ -1355,9 +1390,12 @@ impl FragmentDisplayListBuilding for Fragment {
// There are two situations that need layers: when the fragment has the HAS_LAYER
// flag 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, None))
+ Some(LayerInfo::new(self.layer_id_for_overflow_scroll(),
+ scroll_policy,
+ None,
+ color::transparent()))
} else if self.flags.contains(HAS_LAYER) {
- Some(LayerInfo::new(self.layer_id(), scroll_policy, None))
+ Some(LayerInfo::new(self.layer_id(), scroll_policy, None, color::transparent()))
} else {
None
};
@@ -1367,17 +1405,24 @@ impl FragmentDisplayListBuilding for Fragment {
let establishes_3d_context = scrolls_overflow_area ||
transform_style == transform_style::T::flat;
- Arc::new(StackingContext::new(display_list,
- &border_box,
- &overflow,
- self.effective_z_index(),
- filters,
- self.style().get_effects().mix_blend_mode,
- transform,
- perspective,
- establishes_3d_context,
- scrolls_overflow_area,
- layer_info))
+ let context_type = match mode {
+ StackingContextCreationMode::PseudoFloat => StackingContextType::PseudoFloat,
+ StackingContextCreationMode::PseudoPositioned => StackingContextType::PseudoPositioned,
+ _ => StackingContextType::Real,
+ };
+
+ StackingContext::new(id,
+ context_type,
+ &border_box,
+ &overflow,
+ self.effective_z_index(),
+ filters,
+ self.style().get_effects().mix_blend_mode,
+ transform,
+ perspective,
+ establishes_3d_context,
+ scrolls_overflow_area,
+ layer_info)
}
fn clipping_region_for_children(&self,
@@ -1429,7 +1474,7 @@ impl FragmentDisplayListBuilding for Fragment {
}
fn build_display_list_for_text_fragment(&self,
- display_list: &mut DisplayList,
+ state: &mut DisplayListBuildState,
text_fragment: &ScannedTextFragmentInfo,
text_color: RGBA,
stacking_relative_content_box: &Rect<Au>,
@@ -1460,7 +1505,7 @@ impl FragmentDisplayListBuilding for Fragment {
container_size);
// Create the text display item.
- display_list.content.push_back(DisplayItem::TextClass(box TextDisplayItem {
+ state.add_display_item(DisplayItem::TextClass(box TextDisplayItem {
base: BaseDisplayItem::new(&stacking_relative_content_box,
DisplayItemMetadata::new(self.node, self.style(), cursor),
clip),
@@ -1470,7 +1515,7 @@ impl FragmentDisplayListBuilding for Fragment {
orientation: orientation,
baseline_origin: baseline_origin,
blur_radius: shadow_blur_radius.unwrap_or(Au(0)),
- }));
+ }), DisplayListSection::Content);
// Create display items for text decorations.
let mut text_decorations = self.style()
@@ -1492,21 +1537,21 @@ impl FragmentDisplayListBuilding for Fragment {
stacking_relative_box.start.b = stacking_relative_content_box.start.b +
metrics.ascent - metrics.underline_offset;
stacking_relative_box.size.block = metrics.underline_size;
- self.build_display_list_for_text_decoration(display_list,
+ self.build_display_list_for_text_decoration(state,
underline_color,
&stacking_relative_box,
clip,
- shadow_blur_radius.unwrap_or(Au(0)))
+ shadow_blur_radius.unwrap_or(Au(0)));
}
if let Some(ref overline_color) = text_decorations.overline {
let mut stacking_relative_box = stacking_relative_content_box;
stacking_relative_box.size.block = metrics.underline_size;
- self.build_display_list_for_text_decoration(display_list,
+ self.build_display_list_for_text_decoration(state,
overline_color,
&stacking_relative_box,
clip,
- shadow_blur_radius.unwrap_or(Au(0)))
+ shadow_blur_radius.unwrap_or(Au(0)));
}
if let Some(ref line_through_color) = text_decorations.line_through {
@@ -1514,16 +1559,16 @@ impl FragmentDisplayListBuilding for Fragment {
stacking_relative_box.start.b = stacking_relative_box.start.b + metrics.ascent -
metrics.strikeout_offset;
stacking_relative_box.size.block = metrics.strikeout_size;
- self.build_display_list_for_text_decoration(display_list,
+ self.build_display_list_for_text_decoration(state,
line_through_color,
&stacking_relative_box,
clip,
- shadow_blur_radius.unwrap_or(Au(0)))
+ shadow_blur_radius.unwrap_or(Au(0)));
}
}
fn build_display_list_for_text_decoration(&self,
- display_list: &mut DisplayList,
+ state: &mut DisplayListBuildState,
color: &RGBA,
stacking_relative_box: &LogicalRect<Au>,
clip: &ClippingRegion,
@@ -1537,7 +1582,7 @@ impl FragmentDisplayListBuilding for Fragment {
let stacking_relative_box = stacking_relative_box.to_physical(self.style.writing_mode,
container_size);
let metadata = DisplayItemMetadata::new(self.node, &*self.style, Cursor::DefaultCursor);
- display_list.content.push_back(DisplayItem::BoxShadowClass(box BoxShadowDisplayItem {
+ state.add_display_item(DisplayItem::BoxShadowClass(box BoxShadowDisplayItem {
base: BaseDisplayItem::new(&shadow_bounds(&stacking_relative_box, blur_radius, Au(0)),
metadata,
clip),
@@ -1548,254 +1593,201 @@ impl FragmentDisplayListBuilding for Fragment {
spread_radius: Au(0),
border_radius: Au(0),
clip_mode: BoxShadowClipMode::None,
- }))
+ }), DisplayListSection::Content);
}
}
pub trait BlockFlowDisplayListBuilding {
- fn build_display_list_for_block_base(&mut self,
- display_list: &mut DisplayList,
- layout_context: &LayoutContext,
- border_painting_mode: BorderPaintingMode,
- background_border_level: DisplayListSection);
- fn build_display_list_for_static_block(&mut self,
- display_list: Box<DisplayList>,
- layout_context: &LayoutContext,
- border_painting_mode: BorderPaintingMode,
- background_border_level: DisplayListSection);
- fn build_display_list_for_absolutely_positioned_block(
- &mut self,
- display_list: Box<DisplayList>,
- layout_context: &LayoutContext,
- border_painting_mode: BorderPaintingMode);
- fn build_display_list_for_floating_block(&mut self,
- display_list: Box<DisplayList>,
- layout_context: &LayoutContext,
- border_painting_mode: BorderPaintingMode);
+ fn collect_stacking_contexts_for_block(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>)
+ -> StackingContextId;
fn build_display_list_for_block(&mut self,
- display_list: Box<DisplayList>,
- layout_context: &LayoutContext,
+ state: &mut DisplayListBuildState,
border_painting_mode: BorderPaintingMode);
}
impl BlockFlowDisplayListBuilding for BlockFlow {
- fn build_display_list_for_block_base(&mut self,
- display_list: &mut DisplayList,
- layout_context: &LayoutContext,
- border_painting_mode: BorderPaintingMode,
- background_border_level: DisplayListSection) {
- // Add the box that starts the block context.
- let clip = if self.fragment.establishes_stacking_context() {
- self.base.clip.translate(&-self.base.stacking_relative_position)
- } else {
- self.base.clip.clone()
- };
- self.fragment
- .build_display_list(display_list,
- layout_context,
- &self.base.stacking_relative_position,
- &self.base
- .early_absolute_position_info
- .relative_containing_block_size,
- self.base
- .early_absolute_position_info
- .relative_containing_block_mode,
- border_painting_mode,
- background_border_level,
- &clip,
- &self.base.stacking_relative_position_of_display_port);
-
- // Add children.
- for kid in self.base.children.iter_mut() {
- display_list.append_from(&mut flow::mut_base(kid).display_list_building_result);
+ fn collect_stacking_contexts_for_block(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>)
+ -> StackingContextId {
+ if !self.fragment.establishes_stacking_context() &&
+ !self.establishes_pseudo_stacking_context() {
+ self.base.stacking_context_id = parent_id;
+ self.base.collect_stacking_contexts_for_children(parent_id, contexts);
+ return parent_id;
}
- self.base.build_display_items_for_debugging_tint(display_list, self.fragment.node);
- }
+ let stacking_context_id =
+ StackingContextId::new_of_type(self.fragment.node.id() as usize,
+ self.fragment.fragment_type());
+ self.base.stacking_context_id = stacking_context_id;
- fn build_display_list_for_static_block(&mut self,
- mut display_list: Box<DisplayList>,
- layout_context: &LayoutContext,
- border_painting_mode: BorderPaintingMode,
- background_border_level: DisplayListSection) {
- self.build_display_list_for_block_base(&mut *display_list,
- layout_context,
- border_painting_mode,
- background_border_level);
-
- self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
- let scroll_policy = if self.is_fixed() {
- ScrollPolicy::FixedPosition
- } else {
- ScrollPolicy::Scrollable
- };
-
- Some(DisplayList::new_with_stacking_context(
- self.fragment.create_stacking_context(&self.base,
- display_list,
- scroll_policy,
- StackingContextCreationMode::Normal)))
+ let inner_stacking_context_id = if self.has_scrolling_overflow() {
+ StackingContextId::new_of_type(self.base.flow_id(),
+ self.fragment.fragment_type())
} else {
- if self.fragment.style.get_box().position != position::T::static_ {
- display_list.form_pseudo_stacking_context_for_positioned_content();
- }
- Some(display_list)
- }
- }
+ stacking_context_id
+ };
- fn build_display_list_for_absolutely_positioned_block(
- &mut self,
- mut display_list: Box<DisplayList>,
- layout_context: &LayoutContext,
- border_painting_mode: BorderPaintingMode) {
- // If `overflow: scroll` is in effect, we add this fragment's display items to a new
- // stacking context.
- let outer_display_list_for_overflow_scroll =
- match (self.fragment.style().get_box().overflow_x,
- self.fragment.style().get_box().overflow_y.0) {
- (overflow_x::T::auto, _) |
- (overflow_x::T::scroll, _) |
- (_, overflow_x::T::auto) |
- (_, overflow_x::T::scroll) => {
- // Create a separate display list for our own fragment.
- let mut outer_display_list_for_overflow_scroll = box DisplayList::new();
- let clip = self.base.clip.translate(&-self.base.stacking_relative_position);
- self.fragment.build_display_list(
- &mut outer_display_list_for_overflow_scroll,
- layout_context,
- &self.base.stacking_relative_position,
- &self.base.early_absolute_position_info.relative_containing_block_size,
- self.base.early_absolute_position_info.relative_containing_block_mode,
- border_painting_mode,
- DisplayListSection::BackgroundAndBorders,
- &clip,
- &self.base.stacking_relative_position_of_display_port);
-
- // Add the fragments of our children to the display list we'll use for the inner
- // stacking context.
- for kid in self.base.children.iter_mut() {
- display_list.append_from(&mut flow::mut_base(kid).display_list_building_result);
- }
+ let mut child_contexts = Vec::new();
+ self.base.collect_stacking_contexts_for_children(inner_stacking_context_id,
+ &mut child_contexts);
- Some(outer_display_list_for_overflow_scroll)
- }
- _ => {
- let display_list_section = if self.fragment.establishes_stacking_context() {
- DisplayListSection::BackgroundAndBorders
- } else {
- DisplayListSection::BlockBackgroundsAndBorders
- };
-
- self.build_display_list_for_block_base(&mut *display_list,
- layout_context,
- border_painting_mode,
- display_list_section);
- None
- }
- };
+ if self.establishes_pseudo_stacking_context() {
+ let creation_mode = if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) ||
+ self.fragment.style.get_box().position != position::T::static_ {
+ StackingContextCreationMode::PseudoPositioned
+ } else {
+ assert!(self.base.flags.is_float());
+ StackingContextCreationMode::PseudoFloat
+ };
- if !self.fragment.flags.contains(HAS_LAYER) && !self.fragment.establishes_stacking_context() {
- display_list.form_pseudo_stacking_context_for_positioned_content();
- self.base.display_list_building_result = Some(display_list);
- return;
+ let mut stacking_context =
+ self.fragment.create_stacking_context(stacking_context_id,
+ &self.base,
+ ScrollPolicy::Scrollable,
+ creation_mode);
+ let (mut floating, mut positioned) = child_contexts.into_iter().partition(|context| {
+ context.context_type == StackingContextType::PseudoFloat
+ });
+
+ stacking_context.children.append(&mut floating);
+ contexts.push(stacking_context);
+ contexts.append(&mut positioned);
+ return stacking_context_id;
}
- // If we got here, then we need a new layer.
let scroll_policy = if self.is_fixed() {
ScrollPolicy::FixedPosition
} else {
ScrollPolicy::Scrollable
};
- let stacking_context = match outer_display_list_for_overflow_scroll {
- Some(mut outer_display_list) => {
- 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,
- scroll_policy,
- StackingContextCreationMode::OuterScrollWrapper)
- }
- None => {
- self.fragment.create_stacking_context(
- &self.base,
- display_list,
- scroll_policy,
- StackingContextCreationMode::Normal)
- }
+ let stacking_context = if self.has_scrolling_overflow() {
+ let mut inner_stacking_context = self.fragment.create_stacking_context(
+ inner_stacking_context_id,
+ &self.base,
+ scroll_policy,
+ StackingContextCreationMode::InnerScrollWrapper);
+ inner_stacking_context.children.append(&mut child_contexts);
+
+ let mut outer_stacking_context = self.fragment.create_stacking_context(
+ stacking_context_id,
+ &self.base,
+ scroll_policy,
+ StackingContextCreationMode::OuterScrollWrapper);
+ outer_stacking_context.children.push(inner_stacking_context);
+ outer_stacking_context
+ } else {
+ let mut stacking_context = self.fragment.create_stacking_context(
+ stacking_context_id,
+ &self.base,
+ scroll_policy,
+ StackingContextCreationMode::Normal);
+ stacking_context.children.append(&mut child_contexts);
+ stacking_context
};
- self.base.display_list_building_result =
- Some(DisplayList::new_with_stacking_context(stacking_context));
- }
-
- fn build_display_list_for_floating_block(&mut self,
- mut display_list: Box<DisplayList>,
- layout_context: &LayoutContext,
- border_painting_mode: BorderPaintingMode) {
- self.build_display_list_for_block_base(&mut *display_list,
- layout_context,
- border_painting_mode,
- DisplayListSection::BackgroundAndBorders);
- display_list.form_float_pseudo_stacking_context();
-
- self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
- Some(DisplayList::new_with_stacking_context(
- self.fragment.create_stacking_context(&self.base,
- display_list,
- ScrollPolicy::Scrollable,
- StackingContextCreationMode::Normal)))
- } else {
- if self.fragment.style.get_box().position != position::T::static_ {
- display_list.form_pseudo_stacking_context_for_positioned_content();
- }
- Some(display_list)
- }
+ contexts.push(stacking_context);
+ stacking_context_id
}
fn build_display_list_for_block(&mut self,
- display_list: Box<DisplayList>,
- layout_context: &LayoutContext,
+ state: &mut DisplayListBuildState,
border_painting_mode: BorderPaintingMode) {
- if self.base.flags.is_float() {
- self.build_display_list_for_floating_block(display_list,
- layout_context,
- border_painting_mode);
+ let background_border_section = if self.base.flags.is_float() {
+ DisplayListSection::BackgroundAndBorders
} else if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) {
- self.build_display_list_for_absolutely_positioned_block(display_list,
- layout_context,
- border_painting_mode);
+ if self.fragment.establishes_stacking_context() {
+ DisplayListSection::BackgroundAndBorders
+ } else {
+ DisplayListSection::BlockBackgroundsAndBorders
+ }
} else {
- self.build_display_list_for_static_block(
- display_list,
- layout_context,
- border_painting_mode,
- DisplayListSection::BlockBackgroundsAndBorders);
+ DisplayListSection::BlockBackgroundsAndBorders
+ };
+
+ // Add the box that starts the block context.
+ let clip = if self.fragment.establishes_stacking_context() {
+ self.base.clip.translate(&-self.base.stacking_relative_position)
+ } else {
+ self.base.clip.clone()
+ };
+
+ self.fragment
+ .build_display_list(state,
+ &self.base.stacking_relative_position,
+ &self.base
+ .early_absolute_position_info
+ .relative_containing_block_size,
+ self.base
+ .early_absolute_position_info
+ .relative_containing_block_mode,
+ border_painting_mode,
+ background_border_section,
+ &clip,
+ &self.base.stacking_relative_position_of_display_port);
+
+ // Add children.
+ for kid in self.base.children.iter_mut() {
+ state.append_from(&mut flow::mut_base(kid).display_list_building_result);
}
+
+ self.base.build_display_items_for_debugging_tint(state, self.fragment.node);
}
}
pub trait InlineFlowDisplayListBuilding {
+ fn collect_stacking_contexts_for_inline(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>)
+ -> StackingContextId;
fn build_display_list_for_inline_fragment_at_index(&mut self,
- index: usize,
- display_list: &mut DisplayList,
- layout_context: &LayoutContext);
- fn build_display_list_for_inline(&mut self, layout_context: &LayoutContext);
+ state: &mut DisplayListBuildState,
+ index: usize);
+ fn build_display_list_for_inline(&mut self, state: &mut DisplayListBuildState);
}
impl InlineFlowDisplayListBuilding for InlineFlow {
+ fn collect_stacking_contexts_for_inline(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>)
+ -> StackingContextId {
+ self.base.stacking_context_id = parent_id;
+
+ for mut fragment in self.fragments.fragments.iter_mut() {
+ match fragment.specific {
+ SpecificFragmentInfo::InlineBlock(ref mut block_flow) => {
+ let block_flow = flow_ref::deref_mut(&mut block_flow.flow_ref);
+ block_flow.collect_stacking_contexts(parent_id, contexts);
+ }
+ SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut block_flow) => {
+ let block_flow = flow_ref::deref_mut(&mut block_flow.flow_ref);
+ block_flow.collect_stacking_contexts(parent_id, contexts);
+ }
+ _ if fragment.establishes_stacking_context() => {
+ fragment.stacking_context_id =
+ StackingContextId::new_of_type(fragment.fragment_id(),
+ fragment.fragment_type());
+ contexts.push(fragment.create_stacking_context(
+ fragment.stacking_context_id,
+ &self.base,
+ ScrollPolicy::Scrollable,
+ StackingContextCreationMode::Normal));
+ }
+ _ => fragment.stacking_context_id = parent_id,
+ }
+ }
+ parent_id
+ }
+
fn build_display_list_for_inline_fragment_at_index(&mut self,
- index: usize,
- display_list: &mut DisplayList,
- layout_context: &LayoutContext) {
+ state: &mut DisplayListBuildState,
+ index: usize) {
let fragment = self.fragments.fragments.get_mut(index).unwrap();
- fragment.build_display_list(display_list,
- layout_context,
+ fragment.build_display_list(state,
&self.base.stacking_relative_position,
&self.base
.early_absolute_position_info
@@ -1811,69 +1803,51 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
match fragment.specific {
SpecificFragmentInfo::InlineBlock(ref mut block_flow) => {
let block_flow = flow_ref::deref_mut(&mut block_flow.flow_ref);
- display_list.append_from(
- &mut flow::mut_base(block_flow).display_list_building_result)
+ state.append_from(&mut flow::mut_base(block_flow).display_list_building_result)
}
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut block_flow) => {
let block_flow = flow_ref::deref_mut(&mut block_flow.flow_ref);
- display_list.append_from(
- &mut flow::mut_base(block_flow).display_list_building_result)
+ state.append_from(&mut flow::mut_base(block_flow).display_list_building_result)
}
SpecificFragmentInfo::InlineAbsolute(ref mut block_flow) => {
let block_flow = flow_ref::deref_mut(&mut block_flow.flow_ref);
- display_list.append_from(
- &mut flow::mut_base(block_flow).display_list_building_result)
+ state.append_from(&mut flow::mut_base(block_flow).display_list_building_result)
}
_ => {}
}
}
- fn build_display_list_for_inline(&mut self, layout_context: &LayoutContext) {
+ fn build_display_list_for_inline(&mut self, state: &mut DisplayListBuildState) {
// TODO(#228): Once we form lines and have their cached bounds, we can be smarter and
// not recurse on a line if nothing in it can intersect the dirty region.
debug!("Flow: building display list for {} inline fragments", self.fragments.len());
- let mut display_list = box DisplayList::new();
-
// We iterate using an index here, because we want to avoid doing a doing
// a double-borrow of self (one mutable for the method call and one immutable
// for the self.fragments.fragment iterator itself).
for index in 0..self.fragments.fragments.len() {
- let establishes_stacking_context = {
+ let (establishes_stacking_context, stacking_context_id) = {
let fragment = self.fragments.fragments.get(index).unwrap();
- match fragment.specific {
- SpecificFragmentInfo::InlineBlock(_) |
- SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => false,
- _ => fragment.establishes_stacking_context(),
- }
+ (self.base.stacking_context_id != fragment.stacking_context_id,
+ fragment.stacking_context_id)
};
if establishes_stacking_context {
- let mut fragment_display_list = box DisplayList::new();
- self.build_display_list_for_inline_fragment_at_index(index,
- &mut *fragment_display_list,
- layout_context);
- let fragment = self.fragments.fragments.get(index).unwrap();
- display_list.positioned_content.push_back(DisplayItem::StackingContextClass(
- fragment.create_stacking_context(
- &self.base,
- fragment_display_list,
- ScrollPolicy::Scrollable,
- StackingContextCreationMode::Normal)));
- } else {
- self.build_display_list_for_inline_fragment_at_index(index,
- &mut *display_list,
- layout_context);
+ state.push_stacking_context_id(stacking_context_id);
+ }
+
+ self.build_display_list_for_inline_fragment_at_index(state, index);
+
+ if establishes_stacking_context {
+ state.pop_stacking_context_id();
}
}
if !self.fragments.fragments.is_empty() {
- self.base.build_display_items_for_debugging_tint(&mut *display_list,
+ self.base.build_display_items_for_debugging_tint(state,
self.fragments.fragments[0].node);
}
- self.base.display_list_building_result = Some(display_list);
-
if opts::get().validate_display_list_geometry {
self.base.validate_display_list_geometry();
}
@@ -1881,19 +1855,14 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
}
pub trait ListItemFlowDisplayListBuilding {
- fn build_display_list_for_list_item(&mut self,
- display_list: Box<DisplayList>,
- layout_context: &LayoutContext);
+ fn build_display_list_for_list_item(&mut self, state: &mut DisplayListBuildState);
}
impl ListItemFlowDisplayListBuilding for ListItemFlow {
- fn build_display_list_for_list_item(&mut self,
- mut display_list: Box<DisplayList>,
- layout_context: &LayoutContext) {
+ fn build_display_list_for_list_item(&mut self, state: &mut DisplayListBuildState) {
// Draw the marker, if applicable.
for marker in &mut self.marker_fragments {
- marker.build_display_list(&mut *display_list,
- layout_context,
+ marker.build_display_list(state,
&self.block_flow.base.stacking_relative_position,
&self.block_flow
.base
@@ -1912,38 +1881,30 @@ impl ListItemFlowDisplayListBuilding for ListItemFlow {
}
// Draw the rest of the block.
- self.block_flow.build_display_list_for_block(display_list,
- layout_context,
- BorderPaintingMode::Separate)
+ self.block_flow.build_display_list_for_block(state, BorderPaintingMode::Separate)
}
}
pub trait FlexFlowDisplayListBuilding {
- fn build_display_list_for_flex(&mut self,
- display_list: Box<DisplayList>,
- layout_context: &LayoutContext);
+ fn build_display_list_for_flex(&mut self, state: &mut DisplayListBuildState);
}
impl FlexFlowDisplayListBuilding for FlexFlow {
- fn build_display_list_for_flex(&mut self,
- display_list: Box<DisplayList>,
- layout_context: &LayoutContext) {
+ fn build_display_list_for_flex(&mut self, state: &mut DisplayListBuildState) {
// Draw the rest of the block.
- self.as_mut_block().build_display_list_for_block(display_list,
- layout_context,
- BorderPaintingMode::Separate)
+ self.as_mut_block().build_display_list_for_block(state, BorderPaintingMode::Separate)
}
}
trait BaseFlowDisplayListBuilding {
fn build_display_items_for_debugging_tint(&self,
- display_list: &mut DisplayList,
+ state: &mut DisplayListBuildState,
node: OpaqueNode);
}
impl BaseFlowDisplayListBuilding for BaseFlow {
fn build_display_items_for_debugging_tint(&self,
- display_list: &mut DisplayList,
+ state: &mut DisplayListBuildState,
node: OpaqueNode) {
if !opts::get().show_debug_parallel_layout {
return
@@ -1956,9 +1917,9 @@ impl BaseFlowDisplayListBuilding for BaseFlow {
let mut color = THREAD_TINT_COLORS[thread_id as usize % THREAD_TINT_COLORS.len()];
color.a = 1.0;
- display_list.add_to_section(DisplayItem::BorderClass(box BorderDisplayItem {
+ state.add_display_item(DisplayItem::BorderClass(box BorderDisplayItem {
base: BaseDisplayItem::new(&stacking_context_relative_bounds.inflate(Au::from_px(2),
- Au::from_px(2)),
+ Au::from_px(2)),
DisplayItemMetadata {
node: node,
pointing: None,
@@ -2027,4 +1988,6 @@ pub enum StackingContextCreationMode {
Normal,
OuterScrollWrapper,
InnerScrollWrapper,
+ PseudoPositioned,
+ PseudoFloat,
}
diff --git a/components/layout/flex.rs b/components/layout/flex.rs
index cbb685d046e..c4e08ed6ffa 100644
--- a/components/layout/flex.rs
+++ b/components/layout/flex.rs
@@ -9,7 +9,7 @@
use app_units::Au;
use block::BlockFlow;
use context::LayoutContext;
-use display_list_builder::FlexFlowDisplayListBuilding;
+use display_list_builder::{DisplayListBuildState, FlexFlowDisplayListBuilding};
use euclid::Point2D;
use floats::FloatKind;
use flow;
@@ -19,7 +19,7 @@ use flow::ImmutableFlowUtils;
use flow::{Flow, FlowClass, OpaqueFlow};
use flow::{HAS_LEFT_FLOATED_DESCENDANTS, HAS_RIGHT_FLOATED_DESCENDANTS};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
-use gfx::display_list::DisplayList;
+use gfx::display_list::{StackingContext, StackingContextId};
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
use layout_debug;
use model::MaybeAuto;
@@ -420,14 +420,21 @@ impl Flow for FlexFlow {
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
}
- fn build_display_list(&mut self, layout_context: &LayoutContext) {
- self.build_display_list_for_flex(Box::new(DisplayList::new()), layout_context);
+ fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
+ self.build_display_list_for_flex(state);
if opts::get().validate_display_list_geometry {
self.block_flow.base.validate_display_list_geometry();
}
}
+ fn collect_stacking_contexts(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>)
+ -> StackingContextId {
+ self.block_flow.collect_stacking_contexts(parent_id, contexts)
+ }
+
fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
self.block_flow.repair_style(new_style)
}
diff --git a/components/layout/flow.rs b/components/layout/flow.rs
index b215856b967..480b8689805 100644
--- a/components/layout/flow.rs
+++ b/components/layout/flow.rs
@@ -28,12 +28,13 @@
use app_units::Au;
use block::BlockFlow;
use context::LayoutContext;
+use display_list_builder::DisplayListBuildState;
use euclid::{Point2D, Rect, Size2D};
use floats::Floats;
use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
use flow_ref::{self, FlowRef, WeakFlowRef};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo};
-use gfx::display_list::{ClippingRegion, DisplayList};
+use gfx::display_list::{ClippingRegion, DisplayListEntry, StackingContext, StackingContextId};
use gfx_traits::{LayerId, LayerType};
use incremental::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage};
use inline::InlineFlow;
@@ -221,6 +222,11 @@ pub trait Flow: fmt::Debug + Sync + Send + 'static {
None
}
+ fn collect_stacking_contexts(&mut self,
+ _parent_id: StackingContextId,
+ _: &mut Vec<StackingContext>)
+ -> StackingContextId;
+
/// If this is a float, places it. The default implementation does nothing.
fn place_float_if_applicable<'a>(&mut self, _: &'a LayoutContext<'a>) {}
@@ -284,7 +290,7 @@ pub trait Flow: fmt::Debug + Sync + Send + 'static {
}
/// Phase 5 of reflow: builds display lists.
- fn build_display_list(&mut self, layout_context: &LayoutContext);
+ fn build_display_list(&mut self, state: &mut DisplayListBuildState);
/// Returns the union of all overflow rects of all of this flow's fragments.
fn compute_overflow(&self) -> Overflow;
@@ -361,17 +367,13 @@ pub trait Flow: fmt::Debug + Sync + Send + 'static {
fn generated_containing_block_size(&self, _: OpaqueFlow) -> LogicalSize<Au>;
/// Returns a layer ID for the given fragment.
- #[allow(unsafe_code)]
fn layer_id(&self) -> LayerId {
- let obj = unsafe { mem::transmute::<&&Self, &raw::TraitObject>(&self) };
- LayerId::new_of_type(LayerType::FragmentBody, obj.data as usize)
+ LayerId::new_of_type(LayerType::FragmentBody, base(self).flow_id())
}
/// Returns a layer ID for the given fragment.
- #[allow(unsafe_code)]
fn layer_id_for_overflow_scroll(&self) -> LayerId {
- let obj = unsafe { mem::transmute::<&&Self, &raw::TraitObject>(&self) };
- LayerId::new_of_type(LayerType::OverflowScroll, obj.data as usize)
+ LayerId::new_of_type(LayerType::OverflowScroll, base(self).flow_id())
}
/// Attempts to perform incremental fixup of this flow by replacing its fragment's style with
@@ -924,7 +926,7 @@ pub struct BaseFlow {
pub stacking_relative_position_of_display_port: Rect<Au>,
/// The results of display list building for this flow.
- pub display_list_building_result: Option<Box<DisplayList>>,
+ pub display_list_building_result: Option<Vec<DisplayListEntry>>,
/// The writing mode for this flow.
pub writing_mode: WritingMode,
@@ -934,6 +936,11 @@ pub struct BaseFlow {
/// Various flags for flows, tightly packed to save space.
pub flags: FlowFlags,
+
+ /// The ID of the StackingContext that contains this flow. This is initialized
+ /// to 0, but it assigned during the collect_stacking_contexts phase of display
+ /// list construction.
+ pub stacking_context_id: StackingContextId,
}
impl fmt::Debug for BaseFlow {
@@ -958,7 +965,8 @@ impl fmt::Debug for BaseFlow {
};
write!(f,
- "pos={:?}, overflow={:?}{}{}{}",
+ "sc={:?} pos={:?}, overflow={:?}{}{}{}",
+ self.stacking_context_id,
self.position,
self.overflow,
child_count_string,
@@ -1097,6 +1105,7 @@ impl BaseFlow {
flags: flags,
writing_mode: writing_mode,
thread_id: 0,
+ stacking_context_id: StackingContextId::new(0),
}
}
@@ -1136,24 +1145,37 @@ impl BaseFlow {
.union(&self.overflow.paint);
let bounds = Rect::new(self.stacking_relative_position, position_with_overflow.size);
- let all_items = match self.display_list_building_result {
- Some(ref display_list) => display_list.flatten(),
- None => Vec::new(),
+ let items = match self.display_list_building_result {
+ Some(ref items) => items,
+ None => return,
};
- for item in &all_items {
- 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;
- }
+ for item in items.iter() {
+ let base_item = 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.item,
+ paint_bounds);
}
}
}
+
+ pub fn flow_id(&self) -> usize {
+ return self as *const BaseFlow as usize;
+ }
+
+ pub fn collect_stacking_contexts_for_children(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>) {
+ for kid in self.children.iter_mut() {
+ kid.collect_stacking_contexts(parent_id, contexts);
+ }
+ }
}
impl<'a> ImmutableFlowUtils for &'a Flow {
diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs
index 19d4a687a74..db3a42a0669 100644
--- a/components/layout/fragment.rs
+++ b/components/layout/fragment.rs
@@ -14,7 +14,7 @@ use floats::ClearType;
use flow::{self, Flow};
use flow_ref::{self, FlowRef};
use gfx;
-use gfx::display_list::{BLUR_INFLATION_FACTOR, OpaqueNode};
+use gfx::display_list::{BLUR_INFLATION_FACTOR, FragmentType, OpaqueNode, StackingContextId};
use gfx::text::glyph::CharIndex;
use gfx::text::text_run::{TextRun, TextRunSlice};
use gfx_traits::{LayerId, LayerType};
@@ -117,6 +117,11 @@ pub struct Fragment {
/// A debug ID that is consistent for the life of this fragment (via transform etc).
pub debug_id: u16,
+
+ /// The ID of the StackingContext that contains this fragment. This is initialized
+ /// to 0, but it assigned during the collect_stacking_contexts phase of display
+ /// list construction.
+ pub stacking_context_id: StackingContextId,
}
impl Encodable for Fragment {
@@ -790,6 +795,7 @@ impl Fragment {
pseudo: node.get_pseudo_element_type().strip(),
flags: FragmentFlags::empty(),
debug_id: layout_debug::generate_unique_debug_id(),
+ stacking_context_id: StackingContextId::new(0),
}
}
@@ -816,6 +822,7 @@ impl Fragment {
pseudo: pseudo,
flags: FragmentFlags::empty(),
debug_id: layout_debug::generate_unique_debug_id(),
+ stacking_context_id: StackingContextId::new(0),
}
}
@@ -848,6 +855,7 @@ impl Fragment {
pseudo: self.pseudo.clone(),
flags: FragmentFlags::empty(),
debug_id: self.debug_id,
+ stacking_context_id: StackingContextId::new(0),
}
}
@@ -2139,10 +2147,12 @@ impl Fragment {
overflow_x::T::visible) => false,
(position::T::absolute, _, _, _) |
(position::T::fixed, _, _, _) |
- (position::T::relative, _, _, _) => true,
- (position::T::static_, _, _, _) => {
- false
- }
+ (position::T::relative, _, _, _) |
+ (_, _, overflow_x::T::auto, _) |
+ (_, _, overflow_x::T::scroll, _) |
+ (_, _, _, overflow_x::T::auto) |
+ (_, _, _, overflow_x::T::scroll) => true,
+ (position::T::static_, _, _, _) => false
}
}
@@ -2424,6 +2434,18 @@ impl Fragment {
}
}
+ pub fn fragment_id(&self) -> usize {
+ return self as *const Fragment as usize;
+ }
+
+ pub fn fragment_type(&self) -> FragmentType {
+ match self.pseudo {
+ PseudoElementType::Normal => FragmentType::FragmentBody,
+ PseudoElementType::Before(_) => FragmentType::BeforePseudoContent,
+ PseudoElementType::After(_) => FragmentType::AfterPseudoContent
+ }
+ }
+
pub fn layer_id(&self) -> LayerId {
let layer_type = match self.pseudo {
PseudoElementType::Normal => LayerType::FragmentBody,
diff --git a/components/layout/inline.rs b/components/layout/inline.rs
index bac7f3e07b9..ed07f339720 100644
--- a/components/layout/inline.rs
+++ b/components/layout/inline.rs
@@ -7,6 +7,7 @@
use app_units::Au;
use block::AbsoluteAssignBSizesTraversal;
use context::LayoutContext;
+use display_list_builder::DisplayListBuildState;
use display_list_builder::{FragmentDisplayListBuilding, InlineFlowDisplayListBuilding};
use euclid::{Point2D, Size2D};
use floats::{FloatKind, Floats, PlacementInfo};
@@ -15,7 +16,7 @@ use flow::{self, BaseFlow, Flow, FlowClass, ForceNonfloatedFlag, IS_ABSOLUTELY_P
use flow_ref;
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, Overflow};
use fragment::{SpecificFragmentInfo};
-use gfx::display_list::OpaqueNode;
+use gfx::display_list::{OpaqueNode, StackingContext, StackingContextId};
use gfx::font::FontMetrics;
use gfx::font_context::FontContext;
use incremental::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RESOLVE_GENERATED_CONTENT};
@@ -1747,8 +1748,15 @@ impl Flow for InlineFlow {
fn update_late_computed_block_position_if_necessary(&mut self, _: Au) {}
- fn build_display_list(&mut self, layout_context: &LayoutContext) {
- self.build_display_list_for_inline(layout_context);
+ fn collect_stacking_contexts(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>)
+ -> StackingContextId {
+ self.collect_stacking_contexts_for_inline(parent_id, contexts)
+ }
+
+ fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
+ self.build_display_list_for_inline(state);
for fragment in &mut self.fragments.fragments {
fragment.restyle_damage.remove(REPAINT);
diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs
index 999a979f028..bf4a6ac9745 100644
--- a/components/layout/layout_thread.rs
+++ b/components/layout/layout_thread.rs
@@ -22,11 +22,12 @@ use euclid::size::Size2D;
use flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
use flow_ref::{self, FlowRef};
use fnv::FnvHasher;
-use gfx::display_list::{ClippingRegion, DisplayList, LayerInfo, OpaqueNode, StackingContext};
+use gfx::display_list::{ClippingRegion, DisplayList, LayerInfo};
+use gfx::display_list::{OpaqueNode, StackingContext, StackingContextId, StackingContextType};
use gfx::font;
use gfx::font_cache_thread::FontCacheThread;
use gfx::font_context;
-use gfx::paint_thread::{LayoutToPaintMsg, PaintLayer};
+use gfx::paint_thread::LayoutToPaintMsg;
use gfx_traits::{color, Epoch, LayerId, ScrollPolicy};
use heapsize::HeapSizeOf;
use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REPAINT};
@@ -81,7 +82,7 @@ use util::opts;
use util::thread;
use util::thread_state;
use util::workqueue::WorkQueue;
-use webrender_helpers::WebRenderStackingContextConverter;
+use webrender_helpers::WebRenderDisplayListConverter;
use webrender_traits;
use wrapper::{LayoutNode, NonOpaqueStyleAndLayoutData, ServoLayoutNode, ThreadSafeLayoutNode};
@@ -99,7 +100,7 @@ pub struct LayoutThreadData {
pub constellation_chan: ConstellationChan<ConstellationMsg>,
/// The root stacking context.
- pub stacking_context: Option<Arc<StackingContext>>,
+ pub display_list: Option<Arc<DisplayList>>,
/// Performs CSS selector matching and style resolution.
pub stylist: Box<Stylist>,
@@ -452,7 +453,7 @@ impl LayoutThread {
rw_data: Arc::new(Mutex::new(
LayoutThreadData {
constellation_chan: constellation_chan,
- stacking_context: None,
+ display_list: None,
stylist: stylist,
content_box_response: Rect::zero(),
content_boxes_response: Vec::new(),
@@ -671,12 +672,12 @@ impl LayoutThread {
// FIXME(njn): Just measuring the display tree for now.
let rw_data = possibly_locked_rw_data.lock();
- let stacking_context = rw_data.stacking_context.as_ref();
+ let display_list = rw_data.display_list.as_ref();
let formatted_url = &format!("url({})", *self.url.borrow());
reports.push(Report {
path: path![formatted_url, "layout-thread", "display-list"],
kind: ReportKind::ExplicitJemallocHeapSize,
- size: stacking_context.map_or(0, |sc| sc.heap_size_of_children()),
+ size: display_list.map_or(0, |sc| sc.heap_size_of_children()),
});
// The LayoutThread has a context in TLS...
@@ -860,7 +861,23 @@ impl LayoutThread {
flow::mut_base(flow_ref::deref_mut(layout_root)).clip =
ClippingRegion::from_rect(&data.page_clip_rect);
- sequential::build_display_list_for_subtree(layout_root, shared_layout_context);
+ let mut root_stacking_context =
+ StackingContext::new(StackingContextId::new(0),
+ StackingContextType::Real,
+ &Rect::zero(),
+ &Rect::zero(),
+ 0,
+ filter::T::new(Vec::new()),
+ mix_blend_mode::T::normal,
+ Matrix4::identity(),
+ Matrix4::identity(),
+ true,
+ false,
+ None);
+
+ sequential::build_display_list_for_subtree(layout_root,
+ &mut root_stacking_context,
+ shared_layout_context);
if data.goal == ReflowGoal::ForDisplay {
debug!("Done building display list.");
@@ -875,37 +892,28 @@ impl LayoutThread {
root_flow.overflow.scroll.size
}
};
- let mut display_list = box DisplayList::new();
- display_list.append_from(&mut flow::mut_base(flow_ref::deref_mut(layout_root))
- .display_list_building_result);
let origin = Rect::new(Point2D::new(Au(0), Au(0)), root_size);
- let stacking_context = Arc::new(StackingContext::new(display_list,
- &origin,
- &origin,
- 0,
- filter::T::new(Vec::new()),
- mix_blend_mode::T::normal,
- Matrix4::identity(),
- Matrix4::identity(),
- true,
- false,
- None));
+ root_stacking_context.bounds = origin;
+ root_stacking_context.overflow = origin;
+ root_stacking_context.layer_info = Some(LayerInfo::new(layout_root.layer_id(),
+ ScrollPolicy::Scrollable,
+ None,
+ root_background_color));
+ let display_list = DisplayList::new(
+ root_stacking_context,
+ &mut flow::mut_base(flow_ref::deref_mut(layout_root))
+ .display_list_building_result);
+
if opts::get().dump_display_list {
- stacking_context.print("DisplayList".to_owned());
+ display_list.print();
}
if opts::get().dump_display_list_json {
- println!("{}", serde_json::to_string_pretty(&stacking_context).unwrap());
+ println!("{}", serde_json::to_string_pretty(&display_list).unwrap());
}
- rw_data.stacking_context = Some(stacking_context.clone());
-
- 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);
+ let display_list = Arc::new(display_list);
+ rw_data.display_list = Some(display_list.clone());
debug!("Layout done!");
@@ -920,12 +928,12 @@ impl LayoutThread {
// TODO(gw) For now only create a root scrolling layer!
let root_scroll_layer_id = webrender_traits::ScrollLayerId::new(pipeline_id, 0);
- let sc_id = rw_data.stacking_context.as_ref()
- .unwrap()
- .convert_to_webrender(&self.webrender_api.as_ref().unwrap(),
- pipeline_id,
- epoch,
- Some(root_scroll_layer_id));
+ let sc_id = rw_data.display_list.as_ref()
+ .unwrap()
+ .convert_to_webrender(&self.webrender_api.as_ref().unwrap(),
+ pipeline_id,
+ epoch,
+ Some(root_scroll_layer_id));
let root_background_color = webrender_traits::ColorF::new(root_background_color.r,
root_background_color.g,
root_background_color.b,
@@ -941,7 +949,7 @@ impl LayoutThread {
viewport_size);
} else {
self.paint_chan
- .send(LayoutToPaintMsg::PaintInit(self.epoch, paint_layer))
+ .send(LayoutToPaintMsg::PaintInit(self.epoch, display_list))
.unwrap();
}
}
diff --git a/components/layout/list_item.rs b/components/layout/list_item.rs
index 8caf8dfdd77..701ac4ecdf9 100644
--- a/components/layout/list_item.rs
+++ b/components/layout/list_item.rs
@@ -10,14 +10,14 @@
use app_units::Au;
use block::BlockFlow;
use context::LayoutContext;
-use display_list_builder::ListItemFlowDisplayListBuilding;
+use display_list_builder::{DisplayListBuildState, ListItemFlowDisplayListBuilding};
use euclid::Point2D;
use floats::FloatKind;
use flow::{Flow, FlowClass, OpaqueFlow};
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, GeneratedContentInfo};
use fragment::{Overflow};
use generated_content;
-use gfx::display_list::DisplayList;
+use gfx::display_list::{StackingContext, StackingContextId};
use incremental::RESOLVE_GENERATED_CONTENT;
use inline::InlineMetrics;
use std::sync::Arc;
@@ -142,13 +142,20 @@ impl Flow for ListItemFlow {
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
}
- fn build_display_list(&mut self, layout_context: &LayoutContext) {
- self.build_display_list_for_list_item(box DisplayList::new(), layout_context);
+ fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
+ self.build_display_list_for_list_item(state);
if opts::get().validate_display_list_geometry {
self.block_flow.base.validate_display_list_geometry();
}
}
+ fn collect_stacking_contexts(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>)
+ -> StackingContextId {
+ self.block_flow.collect_stacking_contexts(parent_id, contexts)
+ }
+
fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
self.block_flow.repair_style(new_style)
}
diff --git a/components/layout/multicol.rs b/components/layout/multicol.rs
index 1485ade4aeb..36815c82533 100644
--- a/components/layout/multicol.rs
+++ b/components/layout/multicol.rs
@@ -9,11 +9,13 @@
use app_units::Au;
use block::BlockFlow;
use context::LayoutContext;
+use display_list_builder::DisplayListBuildState;
use euclid::Point2D;
use floats::FloatKind;
use flow::{Flow, FlowClass, OpaqueFlow, mut_base, FragmentationContext};
use flow_ref::{self, FlowRef};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
+use gfx::display_list::{StackingContext, StackingContextId};
use std::cmp::{min, max};
use std::fmt;
use std::sync::Arc;
@@ -177,9 +179,16 @@ impl Flow for MulticolFlow {
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
}
- fn build_display_list(&mut self, layout_context: &LayoutContext) {
+ fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
debug!("build_display_list_multicol");
- self.block_flow.build_display_list(layout_context);
+ self.block_flow.build_display_list(state);
+ }
+
+ fn collect_stacking_contexts(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>)
+ -> StackingContextId {
+ self.block_flow.collect_stacking_contexts(parent_id, contexts)
}
fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
@@ -255,9 +264,16 @@ impl Flow for MulticolColumnFlow {
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
}
- fn build_display_list(&mut self, layout_context: &LayoutContext) {
+ fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
debug!("build_display_list_multicol column");
- self.block_flow.build_display_list(layout_context);
+ self.block_flow.build_display_list(state);
+ }
+
+ fn collect_stacking_contexts(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>)
+ -> StackingContextId {
+ self.block_flow.collect_stacking_contexts(parent_id, contexts)
}
fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
diff --git a/components/layout/query.rs b/components/layout/query.rs
index 0a66a135919..348a3ad556d 100644
--- a/components/layout/query.rs
+++ b/components/layout/query.rs
@@ -11,7 +11,7 @@ use euclid::rect::Rect;
use flow;
use flow_ref::FlowRef;
use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
-use gfx::display_list::{DisplayItemMetadata, OpaqueNode};
+use gfx::display_list::OpaqueNode;
use layout_thread::LayoutThreadData;
use msg::constellation_msg::ConstellationChan;
use opaque_node::OpaqueNodeMethods;
@@ -69,51 +69,40 @@ impl LayoutRPC for LayoutRPCImpl {
/// Requests the node containing the point of interest.
fn hit_test(&self, point: Point2D<f32>) -> Result<HitTestResponse, ()> {
let point = Point2D::new(Au::from_f32_px(point.x), Au::from_f32_px(point.y));
- let resp = {
- let &LayoutRPCImpl(ref rw_data) = self;
- let rw_data = rw_data.lock().unwrap();
- match rw_data.stacking_context {
- None => panic!("no root stacking context!"),
- Some(ref stacking_context) => {
- let mut result = Vec::new();
- stacking_context.hit_test(point, &mut result, true);
- if !result.is_empty() {
- Some(HitTestResponse(result[0].node.to_untrusted_node_address()))
- } else {
- None
- }
- }
- }
+ let &LayoutRPCImpl(ref rw_data) = self;
+ let rw_data = rw_data.lock().unwrap();
+ let result = match rw_data.display_list {
+ None => panic!("Tried to hit test without a DisplayList"),
+ Some(ref display_list) => display_list.hit_test(point),
};
- if resp.is_some() {
- return Ok(resp.unwrap());
+ if result.is_empty() {
+ return Err(());
}
- Err(())
+
+ Ok(HitTestResponse(result[0].node.to_untrusted_node_address()))
}
fn mouse_over(&self, point: Point2D<f32>) -> Result<MouseOverResponse, ()> {
- let mut mouse_over_list: Vec<DisplayItemMetadata> = vec!();
let point = Point2D::new(Au::from_f32_px(point.x), Au::from_f32_px(point.y));
- {
+ let mouse_over_list = {
let &LayoutRPCImpl(ref rw_data) = self;
let rw_data = rw_data.lock().unwrap();
- match rw_data.stacking_context {
- None => panic!("no root stacking context!"),
- Some(ref stacking_context) => {
- stacking_context.hit_test(point, &mut mouse_over_list, false);
- }
- }
+ let result = match rw_data.display_list {
+ None => panic!("Tried to hit test without a DisplayList"),
+ Some(ref display_list) => display_list.hit_test(point),
+ };
// Compute the new cursor.
- let cursor = if !mouse_over_list.is_empty() {
- mouse_over_list[0].pointing.unwrap()
+ let cursor = if !result.is_empty() {
+ result[0].pointing.unwrap()
} else {
Cursor::DefaultCursor
};
let ConstellationChan(ref constellation_chan) = rw_data.constellation_chan;
constellation_chan.send(ConstellationMsg::SetCursor(cursor)).unwrap();
- }
+ result
+ };
if mouse_over_list.is_empty() {
Err(())
diff --git a/components/layout/sequential.rs b/components/layout/sequential.rs
index ad332f30fdd..e0207ee7ca0 100644
--- a/components/layout/sequential.rs
+++ b/components/layout/sequential.rs
@@ -12,6 +12,7 @@ use flow::{self, Flow, ImmutableFlowUtils, InorderFlowTraversal, MutableFlowUtil
use flow_ref::{self, FlowRef};
use fragment::FragmentBorderBoxIterator;
use generated_content::ResolveGeneratedContent;
+use gfx::display_list::StackingContext;
use style::dom::TNode;
use style::traversal::DomTraversalContext;
use traversal::{AssignBSizesAndStoreOverflow, AssignISizes};
@@ -75,28 +76,14 @@ pub fn traverse_flow_tree_preorder(root: &mut FlowRef,
}
pub fn build_display_list_for_subtree(root: &mut FlowRef,
+ root_stacking_context: &mut StackingContext,
shared_layout_context: &SharedLayoutContext) {
- fn doit(flow: &mut Flow,
- compute_absolute_positions: ComputeAbsolutePositions,
- build_display_list: BuildDisplayList) {
- if compute_absolute_positions.should_process(flow) {
- compute_absolute_positions.process(flow);
- }
-
- for kid in flow::mut_base(flow).child_iter() {
- doit(kid, compute_absolute_positions, build_display_list);
- }
-
- if build_display_list.should_process(flow) {
- build_display_list.process(flow);
- }
- }
-
+ let flow_root = flow_ref::deref_mut(root);
let layout_context = LayoutContext::new(shared_layout_context);
- let compute_absolute_positions = ComputeAbsolutePositions { layout_context: &layout_context };
- let build_display_list = BuildDisplayList { layout_context: &layout_context };
-
- doit(flow_ref::deref_mut(root), compute_absolute_positions, build_display_list);
+ flow_root.traverse_preorder(&ComputeAbsolutePositions { layout_context: &layout_context });
+ flow_root.collect_stacking_contexts(root_stacking_context.id,
+ &mut root_stacking_context.children);
+ flow_root.traverse_postorder(&BuildDisplayList { layout_context: &layout_context });
}
pub fn iterate_through_flow_tree_fragment_border_boxes(root: &mut FlowRef,
diff --git a/components/layout/table.rs b/components/layout/table.rs
index 07b606733e8..d17194cc74b 100644
--- a/components/layout/table.rs
+++ b/components/layout/table.rs
@@ -10,12 +10,12 @@ use app_units::Au;
use block::{BlockFlow, CandidateBSizeIterator, ISizeAndMarginsComputer};
use block::{ISizeConstraintInput, ISizeConstraintSolution};
use context::LayoutContext;
-use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode};
+use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode, DisplayListBuildState};
use euclid::Point2D;
use flow::{IMPACTED_BY_RIGHT_FLOATS, ImmutableFlowUtils, OpaqueFlow};
use flow::{self, EarlyAbsolutePositionInfo, Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
-use gfx::display_list::DisplayList;
+use gfx::display_list::{StackingContext, StackingContextId};
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
use layout_debug;
use model::{IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto};
@@ -517,7 +517,7 @@ impl Flow for TableFlow {
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
}
- fn build_display_list(&mut self, layout_context: &LayoutContext) {
+ fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
let border_painting_mode = match self.block_flow
.fragment
.style
@@ -527,9 +527,14 @@ impl Flow for TableFlow {
border_collapse::T::collapse => BorderPaintingMode::Hidden,
};
- self.block_flow.build_display_list_for_block(box DisplayList::new(),
- layout_context,
- border_painting_mode);
+ self.block_flow.build_display_list_for_block(state, border_painting_mode);
+ }
+
+ fn collect_stacking_contexts(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>)
+ -> StackingContextId {
+ self.block_flow.collect_stacking_contexts(parent_id, contexts)
}
fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
diff --git a/components/layout/table_caption.rs b/components/layout/table_caption.rs
index 5c01132ccd6..4bb783154d2 100644
--- a/components/layout/table_caption.rs
+++ b/components/layout/table_caption.rs
@@ -9,9 +9,11 @@
use app_units::Au;
use block::BlockFlow;
use context::LayoutContext;
+use display_list_builder::DisplayListBuildState;
use euclid::Point2D;
use flow::{Flow, FlowClass, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
+use gfx::display_list::{StackingContext, StackingContextId};
use std::fmt;
use std::sync::Arc;
use style::logical_geometry::LogicalSize;
@@ -74,9 +76,16 @@ impl Flow for TableCaptionFlow {
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
}
- fn build_display_list(&mut self, layout_context: &LayoutContext) {
+ fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
debug!("build_display_list_table_caption: same process as block flow");
- self.block_flow.build_display_list(layout_context)
+ self.block_flow.build_display_list(state);
+ }
+
+ fn collect_stacking_contexts(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>)
+ -> StackingContextId {
+ self.block_flow.collect_stacking_contexts(parent_id, contexts)
}
fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs
index d1c33654bbc..0faebcb3cf2 100644
--- a/components/layout/table_cell.rs
+++ b/components/layout/table_cell.rs
@@ -10,11 +10,11 @@ use app_units::Au;
use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
use context::LayoutContext;
use cssparser::Color;
-use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode};
+use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode, DisplayListBuildState};
use euclid::{Point2D, Rect, SideOffsets2D, Size2D};
use flow::{Flow, FlowClass, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
-use gfx::display_list::DisplayList;
+use gfx::display_list::{StackingContext, StackingContextId};
use layout_debug;
use model::MaybeAuto;
use std::fmt;
@@ -174,7 +174,7 @@ impl Flow for TableCellFlow {
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
}
- fn build_display_list(&mut self, layout_context: &LayoutContext) {
+ fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
if !self.visible {
return
}
@@ -188,9 +188,14 @@ impl Flow for TableCellFlow {
border_collapse::T::collapse => BorderPaintingMode::Collapse(&self.collapsed_borders),
};
- self.block_flow.build_display_list_for_block(box DisplayList::new(),
- layout_context,
- border_painting_mode)
+ self.block_flow.build_display_list_for_block(state, border_painting_mode)
+ }
+
+ fn collect_stacking_contexts(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>)
+ -> StackingContextId {
+ self.block_flow.collect_stacking_contexts(parent_id, contexts)
}
fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
diff --git a/components/layout/table_colgroup.rs b/components/layout/table_colgroup.rs
index f62ceb53592..9f1a03e7e0b 100644
--- a/components/layout/table_colgroup.rs
+++ b/components/layout/table_colgroup.rs
@@ -8,9 +8,11 @@
use app_units::Au;
use context::LayoutContext;
+use display_list_builder::DisplayListBuildState;
use euclid::Point2D;
use flow::{BaseFlow, Flow, FlowClass, ForceNonfloatedFlag, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo};
+use gfx::display_list::{StackingContext, StackingContextId};
use layout_debug;
use std::cmp::max;
use std::fmt;
@@ -90,7 +92,14 @@ impl Flow for TableColGroupFlow {
fn update_late_computed_block_position_if_necessary(&mut self, _: Au) {}
// Table columns are invisible.
- fn build_display_list(&mut self, _: &LayoutContext) {}
+ fn build_display_list(&mut self, _: &mut DisplayListBuildState) { }
+
+ fn collect_stacking_contexts(&mut self,
+ parent_id: StackingContextId,
+ _: &mut Vec<StackingContext>)
+ -> StackingContextId {
+ parent_id
+ }
fn repair_style(&mut self, _: &Arc<ComputedValues>) {}
diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs
index ceeed531a8e..0667a3b8fb8 100644
--- a/components/layout/table_row.rs
+++ b/components/layout/table_row.rs
@@ -10,12 +10,12 @@ use app_units::Au;
use block::{BlockFlow, ISizeAndMarginsComputer};
use context::LayoutContext;
use cssparser::{Color, RGBA};
-use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode};
+use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode, DisplayListBuildState};
use euclid::Point2D;
use flow::{self, EarlyAbsolutePositionInfo, Flow, FlowClass, ImmutableFlowUtils, OpaqueFlow};
use flow_list::MutFlowListIterator;
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
-use gfx::display_list::DisplayList;
+use gfx::display_list::{StackingContext, StackingContextId};
use layout_debug;
use model::MaybeAuto;
use rustc_serialize::{Encodable, Encoder};
@@ -420,7 +420,7 @@ impl Flow for TableRowFlow {
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
}
- fn build_display_list(&mut self, layout_context: &LayoutContext) {
+ fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
let border_painting_mode = match self.block_flow
.fragment
.style
@@ -430,9 +430,14 @@ impl Flow for TableRowFlow {
border_collapse::T::collapse => BorderPaintingMode::Hidden,
};
- self.block_flow.build_display_list_for_block(box DisplayList::new(),
- layout_context,
- border_painting_mode);
+ self.block_flow.build_display_list_for_block(state, border_painting_mode);
+ }
+
+ fn collect_stacking_contexts(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>)
+ -> StackingContextId {
+ self.block_flow.collect_stacking_contexts(parent_id, contexts)
}
fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
diff --git a/components/layout/table_rowgroup.rs b/components/layout/table_rowgroup.rs
index 6679b01fe2f..5697a767aff 100644
--- a/components/layout/table_rowgroup.rs
+++ b/components/layout/table_rowgroup.rs
@@ -9,9 +9,11 @@
use app_units::Au;
use block::{BlockFlow, ISizeAndMarginsComputer};
use context::LayoutContext;
+use display_list_builder::DisplayListBuildState;
use euclid::Point2D;
use flow::{Flow, FlowClass, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
+use gfx::display_list::{StackingContext, StackingContextId};
use layout_debug;
use rustc_serialize::{Encodable, Encoder};
use std::fmt;
@@ -208,9 +210,16 @@ impl Flow for TableRowGroupFlow {
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
}
- fn build_display_list(&mut self, layout_context: &LayoutContext) {
+ fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
debug!("build_display_list_table_rowgroup: same process as block flow");
- self.block_flow.build_display_list(layout_context)
+ self.block_flow.build_display_list(state);
+ }
+
+ fn collect_stacking_contexts(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>)
+ -> StackingContextId {
+ self.block_flow.collect_stacking_contexts(parent_id, contexts)
}
fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
diff --git a/components/layout/table_wrapper.rs b/components/layout/table_wrapper.rs
index d8cc8d01aa3..d3224126929 100644
--- a/components/layout/table_wrapper.rs
+++ b/components/layout/table_wrapper.rs
@@ -17,11 +17,13 @@ use app_units::Au;
use block::{AbsoluteNonReplaced, BlockFlow, FloatNonReplaced, ISizeAndMarginsComputer, ISizeConstraintInput};
use block::{ISizeConstraintSolution, MarginsMayCollapseFlag};
use context::LayoutContext;
+use display_list_builder::DisplayListBuildState;
use euclid::Point2D;
use floats::FloatKind;
use flow::{Flow, FlowClass, ImmutableFlowUtils};
use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS, INLINE_POSITION_IS_STATIC, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
+use gfx::display_list::{StackingContext, StackingContextId};
use model::MaybeAuto;
use std::cmp::{max, min};
use std::fmt;
@@ -443,8 +445,15 @@ impl Flow for TableWrapperFlow {
self.block_flow.generated_containing_block_size(flow)
}
- fn build_display_list(&mut self, layout_context: &LayoutContext) {
- self.block_flow.build_display_list(layout_context)
+ fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
+ self.block_flow.build_display_list(state);
+ }
+
+ fn collect_stacking_contexts(&mut self,
+ parent_id: StackingContextId,
+ contexts: &mut Vec<StackingContext>)
+ -> StackingContextId {
+ self.block_flow.collect_stacking_contexts(parent_id, contexts)
}
fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs
index 35269529352..696c43b210b 100644
--- a/components/layout/traversal.rs
+++ b/components/layout/traversal.rs
@@ -9,6 +9,7 @@
use construct::FlowConstructor;
use context::{LayoutContext, SharedLayoutContext};
+use display_list_builder::DisplayListBuildState;
use flow::{PostorderFlowTraversal, PreorderFlowTraversal};
use flow::{self, Flow, CAN_BE_FRAGMENTED};
use gfx::display_list::OpaqueNode;
@@ -222,7 +223,10 @@ pub struct BuildDisplayList<'a> {
impl<'a> PostorderFlowTraversal for BuildDisplayList<'a> {
#[inline]
fn process(&self, flow: &mut Flow) {
- flow.build_display_list(self.layout_context);
+ let mut state = DisplayListBuildState::new(
+ self.layout_context, flow::base(flow).stacking_context_id);
+ flow.build_display_list(&mut state);
+ flow::mut_base(flow).display_list_building_result = Some(state.items);
flow::mut_base(flow).restyle_damage.remove(REPAINT);
}
diff --git a/components/layout/webrender_helpers.rs b/components/layout/webrender_helpers.rs
index a1ab8fac3fe..6d87b56e2e4 100644
--- a/components/layout/webrender_helpers.rs
+++ b/components/layout/webrender_helpers.rs
@@ -12,8 +12,8 @@ use azure::azure_hl::Color;
use euclid::num::Zero;
use euclid::{Point2D, Rect, Size2D};
use gfx::display_list::{BorderRadii, BoxShadowClipMode, ClippingRegion};
-use gfx::display_list::{DisplayItem, DisplayList};
-use gfx::display_list::{GradientStop, StackingContext};
+use gfx::display_list::{DisplayItem, DisplayList, DisplayListEntry, DisplayListSection};
+use gfx::display_list::{DisplayListTraversal, GradientStop, StackingContext, StackingContextType};
use gfx_traits::ScrollPolicy;
use msg::constellation_msg::ConvertPipelineIdToWebRender;
use style::computed_values::filter::{self, Filter};
@@ -21,31 +21,59 @@ use style::computed_values::{image_rendering, mix_blend_mode};
use style::values::computed::BorderStyle;
use webrender_traits;
-pub trait WebRenderStackingContextConverter {
- fn convert_to_webrender(&self,
- api: &webrender_traits::RenderApi,
- pipeline_id: webrender_traits::PipelineId,
- epoch: webrender_traits::Epoch,
- scroll_layer_id: Option<webrender_traits::ScrollLayerId>)
+trait WebRenderStackingContextConverter {
+ fn convert_to_webrender<'a>(&self,
+ traversal: &mut DisplayListTraversal<'a>,
+ api: &webrender_traits::RenderApi,
+ pipeline_id: webrender_traits::PipelineId,
+ epoch: webrender_traits::Epoch,
+ scroll_layer_id: Option<webrender_traits::ScrollLayerId>)
-> webrender_traits::StackingContextId;
+
+ fn convert_children_to_webrender<'a>(&self,
+ traversal: &mut DisplayListTraversal<'a>,
+ api: &webrender_traits::RenderApi,
+ pipeline_id: webrender_traits::PipelineId,
+ epoch: webrender_traits::Epoch,
+ scroll_layer_id: Option<webrender_traits::ScrollLayerId>,
+ builder: &mut webrender_traits::DisplayListBuilder,
+ force_positioned_stacking_level: bool);
+
+ fn web_render_stacking_level(&self) -> webrender_traits::StackingLevel;
}
-trait WebRenderDisplayListConverter {
+pub trait WebRenderDisplayListConverter {
fn convert_to_webrender(&self,
api: &webrender_traits::RenderApi,
pipeline_id: webrender_traits::PipelineId,
- epoch: webrender_traits::Epoch) -> webrender_traits::DisplayListBuilder;
+ epoch: webrender_traits::Epoch,
+ scroll_layer_id: Option<webrender_traits::ScrollLayerId>)
+ -> webrender_traits::StackingContextId;
}
trait WebRenderDisplayItemConverter {
fn convert_to_webrender(&self,
- api: &webrender_traits::RenderApi,
- pipeline_id: webrender_traits::PipelineId,
- epoch: webrender_traits::Epoch,
level: webrender_traits::StackingLevel,
builder: &mut webrender_traits::DisplayListBuilder);
}
+trait WebRenderDisplayListEntryConverter {
+ fn web_render_stacking_level(&self) -> webrender_traits::StackingLevel;
+}
+
+impl WebRenderDisplayListEntryConverter for DisplayListEntry {
+ fn web_render_stacking_level(&self) -> webrender_traits::StackingLevel {
+ match self.section {
+ DisplayListSection::BackgroundAndBorders =>
+ webrender_traits::StackingLevel::BackgroundAndBorders,
+ DisplayListSection::BlockBackgroundsAndBorders =>
+ webrender_traits::StackingLevel::BlockBackgroundAndBorders,
+ DisplayListSection::Content => webrender_traits::StackingLevel::Content,
+ DisplayListSection::Outlines => webrender_traits::StackingLevel::Outlines,
+ }
+ }
+}
+
trait ToBorderStyle {
fn to_border_style(&self) -> webrender_traits::BorderStyle;
}
@@ -235,11 +263,55 @@ impl ToFilterOps for filter::T {
}
impl WebRenderStackingContextConverter for StackingContext {
- fn convert_to_webrender(&self,
- api: &webrender_traits::RenderApi,
- pipeline_id: webrender_traits::PipelineId,
- epoch: webrender_traits::Epoch,
- scroll_layer_id: Option<webrender_traits::ScrollLayerId>)
+ fn convert_children_to_webrender<'a>(&self,
+ traversal: &mut DisplayListTraversal<'a>,
+ api: &webrender_traits::RenderApi,
+ pipeline_id: webrender_traits::PipelineId,
+ epoch: webrender_traits::Epoch,
+ scroll_layer_id: Option<webrender_traits::ScrollLayerId>,
+ builder: &mut webrender_traits::DisplayListBuilder,
+ force_positioned_stacking_level: bool) {
+ for child in self.children.iter() {
+ while let Some(item) = traversal.advance(self) {
+ let stacking_level = if force_positioned_stacking_level {
+ webrender_traits::StackingLevel::PositionedContent
+ } else {
+ item.web_render_stacking_level()
+ };
+ item.item.convert_to_webrender(stacking_level, builder);
+
+ }
+ if child.context_type == StackingContextType::Real {
+ let stacking_context_id = child.convert_to_webrender(traversal,
+ api,
+ pipeline_id,
+ epoch,
+ None);
+ builder.push_stacking_context(child.web_render_stacking_level(),
+ stacking_context_id);
+ } else {
+ child.convert_children_to_webrender(traversal,
+ api,
+ pipeline_id,
+ epoch,
+ scroll_layer_id,
+ builder,
+ true);
+ }
+ }
+
+ while let Some(item) = traversal.advance(self) {
+ item.item.convert_to_webrender(webrender_traits::StackingLevel::PositionedContent,
+ builder);
+ }
+ }
+
+ fn convert_to_webrender<'a>(&self,
+ traversal: &mut DisplayListTraversal<'a>,
+ api: &webrender_traits::RenderApi,
+ pipeline_id: webrender_traits::PipelineId,
+ epoch: webrender_traits::Epoch,
+ scroll_layer_id: Option<webrender_traits::ScrollLayerId>)
-> webrender_traits::StackingContextId {
let scroll_policy = self.layer_info
.map_or(webrender_traits::ScrollPolicy::Scrollable, |info| {
@@ -259,80 +331,50 @@ impl WebRenderStackingContextConverter for StackingContext {
self.establishes_3d_context,
self.blend_mode.to_blend_mode(),
self.filters.to_filter_ops());
-
- let dl_builder = self.display_list.convert_to_webrender(api,
- pipeline_id,
- epoch);
- api.add_display_list(dl_builder, &mut sc, pipeline_id, epoch);
-
+ let mut builder = webrender_traits::DisplayListBuilder::new();
+ self.convert_children_to_webrender(traversal,
+ api,
+ pipeline_id,
+ epoch,
+ scroll_layer_id,
+ &mut builder,
+ false);
+ api.add_display_list(builder, &mut sc, pipeline_id, epoch);
api.add_stacking_context(sc, pipeline_id, epoch)
}
+
+ fn web_render_stacking_level(&self) -> webrender_traits::StackingLevel {
+ match self.context_type {
+ StackingContextType::Real | StackingContextType::PseudoPositioned =>
+ webrender_traits::StackingLevel::PositionedContent,
+ StackingContextType::PseudoFloat => webrender_traits::StackingLevel::Floats,
+ }
+ }
}
-impl WebRenderDisplayListConverter for Box<DisplayList> {
+impl WebRenderDisplayListConverter for DisplayList {
fn convert_to_webrender(&self,
api: &webrender_traits::RenderApi,
pipeline_id: webrender_traits::PipelineId,
- epoch: webrender_traits::Epoch) -> webrender_traits::DisplayListBuilder {
- let mut builder = webrender_traits::DisplayListBuilder::new();
-
- for item in &self.background_and_borders {
- item.convert_to_webrender(api,
- pipeline_id,
- epoch,
- webrender_traits::StackingLevel::BackgroundAndBorders,
- &mut builder);
- }
-
- for item in &self.block_backgrounds_and_borders {
- item.convert_to_webrender(api,
- pipeline_id,
- epoch,
- webrender_traits::StackingLevel::BlockBackgroundAndBorders,
- &mut builder);
- }
-
- for item in &self.floats {
- item.convert_to_webrender(api,
- pipeline_id,
- epoch,
- webrender_traits::StackingLevel::Floats,
- &mut builder);
- }
-
- for item in &self.content {
- item.convert_to_webrender(api,
- pipeline_id,
- epoch,
- webrender_traits::StackingLevel::Content,
- &mut builder);
- }
-
- for item in &self.positioned_content {
- item.convert_to_webrender(api,
- pipeline_id,
- epoch,
- webrender_traits::StackingLevel::PositionedContent,
- &mut builder);
- }
-
- for item in &self.outlines {
- item.convert_to_webrender(api,
- pipeline_id,
- epoch,
- webrender_traits::StackingLevel::Outlines,
- &mut builder);
- }
-
- builder
+ epoch: webrender_traits::Epoch,
+ scroll_layer_id: Option<webrender_traits::ScrollLayerId>)
+ -> webrender_traits::StackingContextId {
+ let mut traversal = DisplayListTraversal {
+ display_list: self,
+ current_item_index: 0,
+ last_item_index: self.list.len() - 1,
+ };
+
+ self.root_stacking_context.convert_to_webrender(&mut traversal,
+ api,
+ pipeline_id,
+ epoch,
+ scroll_layer_id)
}
}
impl WebRenderDisplayItemConverter for DisplayItem {
fn convert_to_webrender(&self,
- api: &webrender_traits::RenderApi,
- pipeline_id: webrender_traits::PipelineId,
- epoch: webrender_traits::Epoch,
level: webrender_traits::StackingLevel,
builder: &mut webrender_traits::DisplayListBuilder) {
match *self {
@@ -469,13 +511,6 @@ impl WebRenderDisplayItemConverter for DisplayItem {
item.base.clip.to_clip_region(),
pipeline_id);
}
- DisplayItem::StackingContextClass(ref item) => {
- let stacking_context_id = item.convert_to_webrender(api,
- pipeline_id,
- epoch,
- None);
- builder.push_stacking_context(level, stacking_context_id);
- }
}
}
}
diff --git a/components/profile/time.rs b/components/profile/time.rs
index 5bb2a0cc0dc..a7164830718 100644
--- a/components/profile/time.rs
+++ b/components/profile/time.rs
@@ -58,6 +58,7 @@ impl Formattable for ProfilerCategory {
ProfilerCategory::LayoutRestyleDamagePropagation |
ProfilerCategory::LayoutNonIncrementalReset |
ProfilerCategory::LayoutGeneratedContent |
+ ProfilerCategory::LayoutDisplayListSorting |
ProfilerCategory::LayoutMain |
ProfilerCategory::LayoutDispListBuild |
ProfilerCategory::LayoutDamagePropagate |
@@ -79,6 +80,7 @@ impl Formattable for ProfilerCategory {
ProfilerCategory::LayoutSelectorMatch => "Selector Matching",
ProfilerCategory::LayoutTreeBuilder => "Tree Building",
ProfilerCategory::LayoutDamagePropagate => "Damage Propagation",
+ ProfilerCategory::LayoutDisplayListSorting => "Sorting Display List",
ProfilerCategory::LayoutGeneratedContent => "Generated Content Resolution",
ProfilerCategory::LayoutMain => "Primary Layout Pass",
ProfilerCategory::LayoutParallelWarmup => "Parallel Warmup",
diff --git a/components/profile_traits/time.rs b/components/profile_traits/time.rs
index 925ebe64c3d..d0adf2cb0d9 100644
--- a/components/profile_traits/time.rs
+++ b/components/profile_traits/time.rs
@@ -48,6 +48,7 @@ pub enum ProfilerCategory {
LayoutTreeBuilder,
LayoutDamagePropagate,
LayoutGeneratedContent,
+ LayoutDisplayListSorting,
LayoutMain,
LayoutParallelWarmup,
LayoutDispListBuild,
diff --git a/components/util/print_tree.rs b/components/util/print_tree.rs
index e94385053b9..7a6ac4f0be9 100644
--- a/components/util/print_tree.rs
+++ b/components/util/print_tree.rs
@@ -57,3 +57,9 @@ impl PrintTree {
}
}
}
+
+impl Drop for PrintTree {
+ fn drop(&mut self) {
+ self.flush_queued_item("└─");
+ }
+}