Wait as late as possible to assign ClipIds

This will allow Servo to create ClipScrollNodes later during display
list construction, which will be necessary once rounded rectangles
are removed from the LocalClip structure. Instead of keeping track
of the ClipId of each ClipScrollNode, we keep track of its index in an
array of ClipScrollNodes. This will allow us to access them without a
hash lookup.
This commit is contained in:
Martin Robinson 2017-10-16 18:36:09 +02:00
parent a296e386af
commit 5937f62352
8 changed files with 365 additions and 274 deletions

View file

@ -33,9 +33,8 @@ use style::values::computed::Filter;
use style_traits::cursor::Cursor; use style_traits::cursor::Cursor;
use text::TextRun; use text::TextRun;
use text::glyph::ByteIndex; use text::glyph::ByteIndex;
use webrender_api::{self, ClipAndScrollInfo, ClipId, ColorF, GradientStop, LocalClip}; use webrender_api::{self, ClipId, ColorF, GradientStop, LocalClip, MixBlendMode, ScrollPolicy};
use webrender_api::{MixBlendMode, ScrollPolicy, ScrollSensitivity, StickyFrameInfo}; use webrender_api::{ScrollSensitivity, StickyFrameInfo, TransformStyle};
use webrender_api::TransformStyle;
pub use style::dom::OpaqueNode; pub use style::dom::OpaqueNode;
@ -43,9 +42,54 @@ pub use style::dom::OpaqueNode;
/// items that involve a blur. This ensures that the display item boundaries include all the ink. /// items that involve a blur. This ensures that the display item boundaries include all the ink.
pub static BLUR_INFLATION_FACTOR: i32 = 3; pub static BLUR_INFLATION_FACTOR: i32 = 3;
/// An index into the vector of ClipScrollNodes. During WebRender conversion these nodes
/// are given ClipIds.
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
pub struct ClipScrollNodeIndex(pub usize);
impl ClipScrollNodeIndex {
pub fn is_root_scroll_node(&self) -> bool {
match *self {
ClipScrollNodeIndex(0) => true,
_ => false,
}
}
pub fn to_define_item(&self) -> DisplayItem {
DisplayItem::DefineClipScrollNode(Box::new(DefineClipScrollNodeItem {
base: BaseDisplayItem::empty(),
node_index: *self,
}))
}
}
/// A set of indices into the clip scroll node vector for a given item.
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
pub struct ClippingAndScrolling {
pub scrolling: ClipScrollNodeIndex,
pub clipping: Option<ClipScrollNodeIndex>,
}
impl ClippingAndScrolling {
pub fn simple(scrolling: ClipScrollNodeIndex) -> ClippingAndScrolling {
ClippingAndScrolling {
scrolling,
clipping: None,
}
}
pub fn new(scrolling: ClipScrollNodeIndex, clipping: ClipScrollNodeIndex) -> ClippingAndScrolling {
ClippingAndScrolling {
scrolling,
clipping: Some(clipping),
}
}
}
#[derive(Deserialize, MallocSizeOf, Serialize)] #[derive(Deserialize, MallocSizeOf, Serialize)]
pub struct DisplayList { pub struct DisplayList {
pub list: Vec<DisplayItem>, pub list: Vec<DisplayItem>,
pub clip_scroll_nodes: Vec<ClipScrollNode>,
} }
impl DisplayList { impl DisplayList {
@ -84,12 +128,19 @@ impl DisplayList {
} }
pub fn print_with_tree(&self, print_tree: &mut PrintTree) { pub fn print_with_tree(&self, print_tree: &mut PrintTree) {
print_tree.new_level("ClipScrollNodes".to_owned());
for node in &self.clip_scroll_nodes {
print_tree.add_item(format!("{:?}", node));
}
print_tree.end_level();
print_tree.new_level("Items".to_owned()); print_tree.new_level("Items".to_owned());
for item in &self.list { for item in &self.list {
print_tree.add_item(format!("{:?} StackingContext: {:?} {:?}", print_tree.add_item(format!("{:?} StackingContext: {:?} {:?}",
item, item,
item.base().stacking_context_id, item.base().stacking_context_id,
item.clip_and_scroll_info())); item.clipping_and_scrolling())
);
} }
print_tree.end_level(); print_tree.end_level();
} }
@ -150,7 +201,7 @@ pub struct StackingContext {
pub scroll_policy: ScrollPolicy, pub scroll_policy: ScrollPolicy,
/// The clip and scroll info for this StackingContext. /// The clip and scroll info for this StackingContext.
pub parent_clip_and_scroll_info: ClipAndScrollInfo, pub parent_clipping_and_scrolling: ClippingAndScrolling,
} }
impl StackingContext { impl StackingContext {
@ -167,44 +218,46 @@ impl StackingContext {
transform_style: TransformStyle, transform_style: TransformStyle,
perspective: Option<Transform3D<f32>>, perspective: Option<Transform3D<f32>>,
scroll_policy: ScrollPolicy, scroll_policy: ScrollPolicy,
parent_clip_and_scroll_info: ClipAndScrollInfo) parent_clipping_and_scrolling: ClippingAndScrolling)
-> StackingContext { -> StackingContext {
StackingContext { StackingContext {
id: id, id,
context_type: context_type, context_type,
bounds: *bounds, bounds: *bounds,
overflow: *overflow, overflow: *overflow,
z_index: z_index, z_index,
filters: filters, filters,
mix_blend_mode: mix_blend_mode, mix_blend_mode,
transform: transform, transform,
transform_style: transform_style, transform_style,
perspective: perspective, perspective,
scroll_policy: scroll_policy, scroll_policy,
parent_clip_and_scroll_info: parent_clip_and_scroll_info, parent_clipping_and_scrolling,
} }
} }
#[inline] #[inline]
pub fn root(pipeline_id: PipelineId) -> StackingContext { pub fn root() -> StackingContext {
StackingContext::new(StackingContextId::root(), StackingContext::new(
StackingContextType::Real, StackingContextId::root(),
&Rect::zero(), StackingContextType::Real,
&Rect::zero(), &Rect::zero(),
0, &Rect::zero(),
vec![], 0,
MixBlendMode::Normal, vec![],
None, MixBlendMode::Normal,
TransformStyle::Flat, None,
None, TransformStyle::Flat,
ScrollPolicy::Scrollable, None,
pipeline_id.root_clip_and_scroll_info()) ScrollPolicy::Scrollable,
ClippingAndScrolling::simple(ClipScrollNodeIndex(0))
)
} }
pub fn to_display_list_items(self, pipeline_id: PipelineId) -> (DisplayItem, DisplayItem) { pub fn to_display_list_items(self) -> (DisplayItem, DisplayItem) {
let mut base_item = BaseDisplayItem::empty(pipeline_id); let mut base_item = BaseDisplayItem::empty();
base_item.stacking_context_id = self.id; base_item.stacking_context_id = self.id;
base_item.clip_and_scroll_info = self.parent_clip_and_scroll_info; base_item.clipping_and_scrolling = self.parent_clipping_and_scrolling;
let pop_item = DisplayItem::PopStackingContext(Box::new( let pop_item = DisplayItem::PopStackingContext(Box::new(
PopStackingContextItem { PopStackingContextItem {
@ -280,10 +333,10 @@ pub enum ClipScrollNodeType {
pub struct ClipScrollNode { pub struct ClipScrollNode {
/// The WebRender clip id of this scroll root based on the source of this clip /// The WebRender clip id of this scroll root based on the source of this clip
/// and information about the fragment. /// and information about the fragment.
pub id: ClipId, pub id: Option<ClipId>,
/// The unique ID of the parent of this ClipScrollNode. /// The index of the parent of this ClipScrollNode.
pub parent_id: ClipId, pub parent_index: ClipScrollNodeIndex,
/// The position of this scroll root's frame in the parent stacking context. /// The position of this scroll root's frame in the parent stacking context.
pub clip: ClippingRegion, pub clip: ClippingRegion,
@ -295,16 +348,6 @@ pub struct ClipScrollNode {
pub node_type: ClipScrollNodeType, pub node_type: ClipScrollNodeType,
} }
impl ClipScrollNode {
pub fn to_define_item(&self, pipeline_id: PipelineId) -> DisplayItem {
DisplayItem::DefineClipScrollNode(Box::new(DefineClipScrollNodeItem {
base: BaseDisplayItem::empty(pipeline_id),
node: self.clone(),
}))
}
}
/// One drawing command in the list. /// One drawing command in the list.
#[derive(Clone, Deserialize, MallocSizeOf, Serialize)] #[derive(Clone, Deserialize, MallocSizeOf, Serialize)]
pub enum DisplayItem { pub enum DisplayItem {
@ -343,7 +386,7 @@ pub struct BaseDisplayItem {
pub stacking_context_id: StackingContextId, pub stacking_context_id: StackingContextId,
/// The clip and scroll info for this item. /// The clip and scroll info for this item.
pub clip_and_scroll_info: ClipAndScrollInfo, pub clipping_and_scrolling: ClippingAndScrolling,
} }
impl BaseDisplayItem { impl BaseDisplayItem {
@ -353,7 +396,7 @@ impl BaseDisplayItem {
local_clip: LocalClip, local_clip: LocalClip,
section: DisplayListSection, section: DisplayListSection,
stacking_context_id: StackingContextId, stacking_context_id: StackingContextId,
clip_and_scroll_info: ClipAndScrollInfo) clipping_and_scrolling: ClippingAndScrolling)
-> BaseDisplayItem { -> BaseDisplayItem {
BaseDisplayItem { BaseDisplayItem {
bounds: *bounds, bounds: *bounds,
@ -361,12 +404,12 @@ impl BaseDisplayItem {
local_clip: local_clip, local_clip: local_clip,
section: section, section: section,
stacking_context_id: stacking_context_id, stacking_context_id: stacking_context_id,
clip_and_scroll_info: clip_and_scroll_info, clipping_and_scrolling: clipping_and_scrolling,
} }
} }
#[inline(always)] #[inline(always)]
pub fn empty(pipeline_id: PipelineId) -> BaseDisplayItem { pub fn empty() -> BaseDisplayItem {
BaseDisplayItem { BaseDisplayItem {
bounds: TypedRect::zero(), bounds: TypedRect::zero(),
metadata: DisplayItemMetadata { metadata: DisplayItemMetadata {
@ -376,7 +419,7 @@ impl BaseDisplayItem {
local_clip: LocalClip::from(max_rect().to_rectf()), local_clip: LocalClip::from(max_rect().to_rectf()),
section: DisplayListSection::Content, section: DisplayListSection::Content,
stacking_context_id: StackingContextId::root(), stacking_context_id: StackingContextId::root(),
clip_and_scroll_info: pipeline_id.root_clip_and_scroll_info(), clipping_and_scrolling: ClippingAndScrolling::simple(ClipScrollNodeIndex(0)),
} }
} }
} }
@ -929,7 +972,7 @@ pub struct DefineClipScrollNodeItem {
pub base: BaseDisplayItem, pub base: BaseDisplayItem,
/// The scroll root that this item starts. /// The scroll root that this item starts.
pub node: ClipScrollNode, pub node_index: ClipScrollNodeIndex,
} }
/// How a box shadow should be clipped. /// How a box shadow should be clipped.
@ -963,12 +1006,12 @@ impl DisplayItem {
} }
} }
pub fn scroll_node_id(&self) -> ClipId { pub fn scroll_node_index(&self) -> ClipScrollNodeIndex {
self.base().clip_and_scroll_info.scroll_node_id self.base().clipping_and_scrolling.scrolling
} }
pub fn clip_and_scroll_info(&self) -> ClipAndScrollInfo { pub fn clipping_and_scrolling(&self) -> ClippingAndScrolling {
self.base().clip_and_scroll_info self.base().clipping_and_scrolling
} }
pub fn stacking_context_id(&self) -> StackingContextId { pub fn stacking_context_id(&self) -> StackingContextId {
@ -1003,7 +1046,7 @@ impl fmt::Debug for DisplayItem {
} }
if let DisplayItem::DefineClipScrollNode(ref item) = *self { if let DisplayItem::DefineClipScrollNode(ref item) = *self {
return write!(f, "DefineClipScrollNode({:?}", item.node); return write!(f, "DefineClipScrollNode({:?}", item.node_index);
} }
write!(f, "{} @ {:?} {:?}", write!(f, "{} @ {:?} {:?}",

View file

@ -14,8 +14,7 @@ use app_units::{AU_PER_PX, Au};
use block::{BlockFlow, BlockStackingContextType}; use block::{BlockFlow, BlockStackingContextType};
use canvas_traits::canvas::{CanvasMsg, FromLayoutMsg}; use canvas_traits::canvas::{CanvasMsg, FromLayoutMsg};
use context::LayoutContext; use context::LayoutContext;
use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Transform3D, TypedSize2D}; use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Transform3D, TypedRect, TypedSize2D, Vector2D};
use euclid::Vector2D;
use flex::FlexFlow; use flex::FlexFlow;
use flow::{BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED}; use flow::{BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED};
use flow_ref::FlowRef; use flow_ref::FlowRef;
@ -25,9 +24,10 @@ use fragment::SpecificFragmentInfo;
use gfx::display_list; use gfx::display_list;
use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDetails, BorderDisplayItem}; use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDetails, BorderDisplayItem};
use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClipScrollNode}; use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClipScrollNode};
use gfx::display_list::{ClipScrollNodeType, ClippingRegion, DisplayItem, DisplayItemMetadata}; use gfx::display_list::{ClipScrollNodeIndex, ClippingAndScrolling, ClipScrollNodeType};
use gfx::display_list::{DisplayList, DisplayListSection, GradientDisplayItem, IframeDisplayItem}; use gfx::display_list::{ClippingRegion, DisplayItem, DisplayItemMetadata, DisplayList};
use gfx::display_list::{ImageBorder, ImageDisplayItem, LineDisplayItem, NormalBorder, OpaqueNode}; use gfx::display_list::{DisplayListSection, GradientDisplayItem, IframeDisplayItem, ImageBorder};
use gfx::display_list::{ImageDisplayItem, LineDisplayItem, NormalBorder, OpaqueNode};
use gfx::display_list::{PopAllTextShadowsDisplayItem, PushTextShadowDisplayItem}; use gfx::display_list::{PopAllTextShadowsDisplayItem, PushTextShadowDisplayItem};
use gfx::display_list::{RadialGradientDisplayItem, SolidColorDisplayItem, StackingContext}; use gfx::display_list::{RadialGradientDisplayItem, SolidColorDisplayItem, StackingContext};
use gfx::display_list::{StackingContextType, TextDisplayItem, TextOrientation, WebRenderImageInfo}; use gfx::display_list::{StackingContextType, TextDisplayItem, TextOrientation, WebRenderImageInfo};
@ -71,8 +71,8 @@ use style_traits::CSSPixel;
use style_traits::ToCss; use style_traits::ToCss;
use style_traits::cursor::Cursor; use style_traits::cursor::Cursor;
use table_cell::CollapsedBordersForCell; use table_cell::CollapsedBordersForCell;
use webrender_api::{ClipAndScrollInfo, ClipId, ClipMode, ColorF, ComplexClipRegion, GradientStop}; use webrender_api::{ClipId, ClipMode, ColorF, ComplexClipRegion, GradientStop, LineStyle};
use webrender_api::{LineStyle, LocalClip, RepeatMode, ScrollPolicy, ScrollSensitivity, StickyFrameInfo}; use webrender_api::{LocalClip, RepeatMode, ScrollPolicy, ScrollSensitivity, StickyFrameInfo};
use webrender_api::StickySideConstraint; use webrender_api::StickySideConstraint;
use webrender_helpers::{ToBorderRadius, ToMixBlendMode, ToRectF, ToTransformStyle}; use webrender_helpers::{ToBorderRadius, ToMixBlendMode, ToRectF, ToTransformStyle};
@ -146,8 +146,9 @@ pub struct InlineNodeBorderInfo {
#[derive(Debug)] #[derive(Debug)]
struct StackingContextInfo { struct StackingContextInfo {
children: Vec<StackingContext>, children: Vec<StackingContext>,
clip_scroll_nodes: Vec<ClipScrollNode>, clip_scroll_nodes: Vec<ClipScrollNodeIndex>,
} }
impl StackingContextInfo { impl StackingContextInfo {
fn new() -> StackingContextInfo { fn new() -> StackingContextInfo {
StackingContextInfo { StackingContextInfo {
@ -171,8 +172,7 @@ pub struct StackingContextCollectionState {
/// StackingContext and ClipScrollNode children for each StackingContext. /// StackingContext and ClipScrollNode children for each StackingContext.
stacking_context_info: FnvHashMap<StackingContextId, StackingContextInfo>, stacking_context_info: FnvHashMap<StackingContextId, StackingContextInfo>,
/// A map establishing the parent child relationship of every ClipScrollNode. pub clip_scroll_nodes: Vec<ClipScrollNode>,
pub clip_scroll_node_parents: FnvHashMap<ClipId, ClipId>,
/// The current stacking context id, used to keep track of state when building. /// The current stacking context id, used to keep track of state when building.
/// recursively building and processing the display list. /// recursively building and processing the display list.
@ -186,12 +186,12 @@ pub struct StackingContextCollectionState {
/// The current clip and scroll info, used to keep track of state when /// The current clip and scroll info, used to keep track of state when
/// recursively building and processing the display list. /// recursively building and processing the display list.
pub current_clip_and_scroll_info: ClipAndScrollInfo, pub current_clipping_and_scrolling: ClippingAndScrolling,
/// The clip and scroll info of the first ancestor which defines a containing block. /// The clip and scroll info of the first ancestor which defines a containing block.
/// This is necessary because absolutely positioned items should be clipped /// This is necessary because absolutely positioned items should be clipped
/// by their containing block's scroll root. /// by their containing block's scroll root.
pub containing_block_clip_and_scroll_info: ClipAndScrollInfo, pub containing_block_clipping_and_scrolling: ClippingAndScrolling,
/// A stack of clips used to cull display list entries that are outside the /// A stack of clips used to cull display list entries that are outside the
/// rendered region. /// rendered region.
@ -207,17 +207,28 @@ pub struct StackingContextCollectionState {
impl StackingContextCollectionState { impl StackingContextCollectionState {
pub fn new(pipeline_id: PipelineId) -> StackingContextCollectionState { pub fn new(pipeline_id: PipelineId) -> StackingContextCollectionState {
let root_clip_info = ClipAndScrollInfo::simple(pipeline_id.root_scroll_node()); let root_clip_indices = ClippingAndScrolling::simple(ClipScrollNodeIndex(0));
// This is just a dummy node to take up a slot in the array. WebRender
// takes care of adding this root node and it can be ignored during DL conversion.
let root_node = ClipScrollNode {
id: Some(ClipId::root_scroll_node(pipeline_id.to_webrender())),
parent_index: ClipScrollNodeIndex(0),
clip: ClippingRegion::from_rect(&TypedRect::zero()),
content_rect: Rect::zero(),
node_type: ClipScrollNodeType::ScrollFrame(ScrollSensitivity::ScriptAndInputEvents),
};
StackingContextCollectionState { StackingContextCollectionState {
pipeline_id: pipeline_id, pipeline_id: pipeline_id,
root_stacking_context: StackingContext::root(pipeline_id), root_stacking_context: StackingContext::root(),
stacking_context_info: FnvHashMap::default(), stacking_context_info: FnvHashMap::default(),
clip_scroll_node_parents: FnvHashMap::default(), clip_scroll_nodes: vec![root_node],
current_stacking_context_id: StackingContextId::root(), current_stacking_context_id: StackingContextId::root(),
current_real_stacking_context_id: StackingContextId::root(), current_real_stacking_context_id: StackingContextId::root(),
next_stacking_context_id: StackingContextId::root().next(), next_stacking_context_id: StackingContextId::root().next(),
current_clip_and_scroll_info: root_clip_info, current_clipping_and_scrolling: root_clip_indices,
containing_block_clip_and_scroll_info: root_clip_info, containing_block_clipping_and_scrolling: root_clip_indices,
clip_stack: Vec::new(), clip_stack: Vec::new(),
containing_block_clip_stack: Vec::new(), containing_block_clip_stack: Vec::new(),
parent_stacking_relative_content_box: Rect::zero(), parent_stacking_relative_content_box: Rect::zero(),
@ -238,20 +249,18 @@ impl StackingContextCollectionState {
info.children.push(stacking_context); info.children.push(stacking_context);
} }
fn has_clip_scroll_node(&mut self, id: ClipId) -> bool { fn add_clip_scroll_node(&mut self, clip_scroll_node: ClipScrollNode) -> ClipScrollNodeIndex {
self.clip_scroll_node_parents.contains_key(&id)
}
fn add_clip_scroll_node(&mut self, clip_scroll_node: ClipScrollNode) {
// We want the scroll root to be defined before any possible item that could use it, // We want the scroll root to be defined before any possible item that could use it,
// so we make sure that it is added to the beginning of the parent "real" (non-pseudo) // so we make sure that it is added to the beginning of the parent "real" (non-pseudo)
// stacking context. This ensures that item reordering will not result in an item using // stacking context. This ensures that item reordering will not result in an item using
// the scroll root before it is defined. // the scroll root before it is defined.
self.clip_scroll_node_parents.insert(clip_scroll_node.id, clip_scroll_node.parent_id); self.clip_scroll_nodes.push(clip_scroll_node);
let index = ClipScrollNodeIndex(self.clip_scroll_nodes.len() - 1);
let info = self.stacking_context_info let info = self.stacking_context_info
.entry(self.current_real_stacking_context_id) .entry(self.current_real_stacking_context_id)
.or_insert(StackingContextInfo::new()); .or_insert(StackingContextInfo::new());
info.clip_scroll_nodes.push(clip_scroll_node); info.clip_scroll_nodes.push(index);
index
} }
} }
@ -265,8 +274,8 @@ pub struct DisplayListBuildState<'a> {
/// StackingContext and ClipScrollNode children for each StackingContext. /// StackingContext and ClipScrollNode children for each StackingContext.
stacking_context_info: FnvHashMap<StackingContextId, StackingContextInfo>, stacking_context_info: FnvHashMap<StackingContextId, StackingContextInfo>,
/// A map establishing the parent child relationship of every ClipScrollNode. /// A vector of ClipScrollNodes which will be given ids during WebRender DL conversion.
pub clip_scroll_node_parents: FnvHashMap<ClipId, ClipId>, pub clip_scroll_nodes: Vec<ClipScrollNode>,
/// The items in this display list. /// The items in this display list.
pub items: FnvHashMap<StackingContextId, Vec<DisplayItem>>, pub items: FnvHashMap<StackingContextId, Vec<DisplayItem>>,
@ -281,7 +290,7 @@ pub struct DisplayListBuildState<'a> {
/// The current clip and scroll info, used to keep track of state when /// The current clip and scroll info, used to keep track of state when
/// recursively building and processing the display list. /// recursively building and processing the display list.
pub current_clip_and_scroll_info: ClipAndScrollInfo, pub current_clipping_and_scrolling: ClippingAndScrolling,
/// Vector containing iframe sizes, used to inform the constellation about /// Vector containing iframe sizes, used to inform the constellation about
/// new iframe sizes /// new iframe sizes
@ -292,16 +301,16 @@ impl<'a> DisplayListBuildState<'a> {
pub fn new(layout_context: &'a LayoutContext, pub fn new(layout_context: &'a LayoutContext,
state: StackingContextCollectionState) state: StackingContextCollectionState)
-> DisplayListBuildState<'a> { -> DisplayListBuildState<'a> {
let root_clip_info = ClipAndScrollInfo::simple(layout_context.id.root_scroll_node()); let root_clip_indices = ClippingAndScrolling::simple(ClipScrollNodeIndex(0));
DisplayListBuildState { DisplayListBuildState {
layout_context: layout_context, layout_context: layout_context,
root_stacking_context: state.root_stacking_context, root_stacking_context: state.root_stacking_context,
items: FnvHashMap::default(), items: FnvHashMap::default(),
stacking_context_info: state.stacking_context_info, stacking_context_info: state.stacking_context_info,
clip_scroll_node_parents: state.clip_scroll_node_parents, clip_scroll_nodes: state.clip_scroll_nodes,
processing_scrolling_overflow_element: false, processing_scrolling_overflow_element: false,
current_stacking_context_id: StackingContextId::root(), current_stacking_context_id: StackingContextId::root(),
current_clip_and_scroll_info: root_clip_info, current_clipping_and_scrolling: root_clip_indices,
iframe_sizes: Vec::new(), iframe_sizes: Vec::new(),
} }
} }
@ -311,13 +320,12 @@ impl<'a> DisplayListBuildState<'a> {
items.push(display_item); items.push(display_item);
} }
fn parent_clip_scroll_node_id(&self, clip_scroll_node_id: ClipId) -> ClipId { fn parent_clip_scroll_node_index(&self, index: ClipScrollNodeIndex) -> ClipScrollNodeIndex {
if clip_scroll_node_id.is_root_scroll_node() { if index.is_root_scroll_node() {
return clip_scroll_node_id; return index;
} }
debug_assert!(self.clip_scroll_node_parents.contains_key(&clip_scroll_node_id)); self.clip_scroll_nodes[index.0].parent_index
*self.clip_scroll_node_parents.get(&clip_scroll_node_id).unwrap()
} }
fn is_background_or_border_of_clip_scroll_node(&self, section: DisplayListSection) -> bool { fn is_background_or_border_of_clip_scroll_node(&self, section: DisplayListSection) -> bool {
@ -333,10 +341,11 @@ impl<'a> DisplayListBuildState<'a> {
cursor: Option<Cursor>, cursor: Option<Cursor>,
section: DisplayListSection) section: DisplayListSection)
-> BaseDisplayItem { -> BaseDisplayItem {
let clip_and_scroll_info = if self.is_background_or_border_of_clip_scroll_node(section) { let clipping_and_scrolling = if self.is_background_or_border_of_clip_scroll_node(section) {
ClipAndScrollInfo::simple(self.parent_clip_scroll_node_id(self.current_clip_and_scroll_info.scroll_node_id)) ClippingAndScrolling::simple(
self.parent_clip_scroll_node_index(self.current_clipping_and_scrolling.scrolling))
} else { } else {
self.current_clip_and_scroll_info self.current_clipping_and_scrolling
}; };
BaseDisplayItem::new(&bounds, BaseDisplayItem::new(&bounds,
@ -347,18 +356,18 @@ impl<'a> DisplayListBuildState<'a> {
clip, clip,
section, section,
self.current_stacking_context_id, self.current_stacking_context_id,
clip_and_scroll_info) clipping_and_scrolling)
} }
pub fn to_display_list(mut self) -> DisplayList { pub fn to_display_list(mut self) -> DisplayList {
let mut list = Vec::new(); let mut list = Vec::new();
let root_context = mem::replace(&mut self.root_stacking_context, let root_context = mem::replace(&mut self.root_stacking_context, StackingContext::root());
StackingContext::root(self.layout_context.id));
self.to_display_list_for_stacking_context(&mut list, root_context); self.to_display_list_for_stacking_context(&mut list, root_context);
DisplayList { DisplayList {
list: list, list: list,
clip_scroll_nodes: self.clip_scroll_nodes,
} }
} }
@ -374,14 +383,13 @@ impl<'a> DisplayListBuildState<'a> {
info.children.sort(); info.children.sort();
let pipeline_id = self.layout_context.id;
if stacking_context.context_type != StackingContextType::Real { if stacking_context.context_type != StackingContextType::Real {
list.extend(info.clip_scroll_nodes.into_iter().map(|root| root.to_define_item(pipeline_id))); list.extend(info.clip_scroll_nodes.into_iter().map(|index| index.to_define_item()));
self.to_display_list_for_items(list, child_items, info.children); self.to_display_list_for_items(list, child_items, info.children);
} else { } else {
let (push_item, pop_item) = stacking_context.to_display_list_items(pipeline_id); let (push_item, pop_item) = stacking_context.to_display_list_items();
list.push(push_item); list.push(push_item);
list.extend(info.clip_scroll_nodes.into_iter().map(|root| root.to_define_item(pipeline_id))); list.extend(info.clip_scroll_nodes.into_iter().map(|index| index.to_define_item()));
self.to_display_list_for_items(list, child_items, info.children); self.to_display_list_for_items(list, child_items, info.children);
list.push(pop_item); list.push(pop_item);
} }
@ -612,13 +620,14 @@ pub trait FragmentDisplayListBuilding {
clip: &Rect<Au>); clip: &Rect<Au>);
/// Creates a stacking context for associated fragment. /// Creates a stacking context for associated fragment.
fn create_stacking_context(&self, fn create_stacking_context(
id: StackingContextId, &self,
base_flow: &BaseFlow, id: StackingContextId,
scroll_policy: ScrollPolicy, base_flow: &BaseFlow,
context_type: StackingContextType, scroll_policy: ScrollPolicy,
parent_clip_and_scroll_info: ClipAndScrollInfo) context_type: StackingContextType,
-> StackingContext; parent_clipping_and_scrolling: ClippingAndScrolling
) -> StackingContext;
fn unique_id(&self, id_type: IdType) -> u64; fn unique_id(&self, id_type: IdType) -> u64;
@ -2175,13 +2184,14 @@ impl FragmentDisplayListBuilding for Fragment {
} }
} }
fn create_stacking_context(&self, fn create_stacking_context(
id: StackingContextId, &self,
base_flow: &BaseFlow, id: StackingContextId,
scroll_policy: ScrollPolicy, base_flow: &BaseFlow,
context_type: StackingContextType, scroll_policy: ScrollPolicy,
parent_clip_and_scroll_info: ClipAndScrollInfo) context_type: StackingContextType,
-> StackingContext { parent_clipping_and_scrolling: ClippingAndScrolling
) -> StackingContext {
let border_box = let border_box =
self.stacking_relative_border_box(&base_flow.stacking_relative_position, self.stacking_relative_border_box(&base_flow.stacking_relative_position,
&base_flow.early_absolute_position_info &base_flow.early_absolute_position_info
@ -2203,18 +2213,20 @@ impl FragmentDisplayListBuilding for Fragment {
filters.push(Filter::Opacity(effects.opacity.into())) filters.push(Filter::Opacity(effects.opacity.into()))
} }
StackingContext::new(id, StackingContext::new(
context_type, id,
&border_box, context_type,
&overflow, &border_box,
self.effective_z_index(), &overflow,
filters.into(), self.effective_z_index(),
self.style().get_effects().mix_blend_mode.to_mix_blend_mode(), filters.into(),
self.transform_matrix(&border_box), self.style().get_effects().mix_blend_mode.to_mix_blend_mode(),
self.style().get_used_transform_style().to_transform_style(), self.transform_matrix(&border_box),
self.perspective_matrix(&border_box), self.style().get_used_transform_style().to_transform_style(),
scroll_policy, self.perspective_matrix(&border_box),
parent_clip_and_scroll_info) scroll_policy,
parent_clipping_and_scrolling
)
} }
fn build_display_list_for_text_fragment(&self, fn build_display_list_for_text_fragment(&self,
@ -2417,7 +2429,7 @@ pub trait BlockFlowDisplayListBuilding {
preserved_state: &mut SavedStackingContextCollectionState, preserved_state: &mut SavedStackingContextCollectionState,
stacking_context_type: BlockStackingContextType, stacking_context_type: BlockStackingContextType,
flags: StackingContextCollectionFlags) flags: StackingContextCollectionFlags)
-> ClipAndScrollInfo; -> ClippingAndScrolling;
fn setup_clip_scroll_node_for_position(&mut self, fn setup_clip_scroll_node_for_position(&mut self,
state: &mut StackingContextCollectionState, state: &mut StackingContextCollectionState,
border_box: &Rect<Au>); border_box: &Rect<Au>);
@ -2428,14 +2440,18 @@ pub trait BlockFlowDisplayListBuilding {
state: &mut StackingContextCollectionState, state: &mut StackingContextCollectionState,
preserved_state: &mut SavedStackingContextCollectionState, preserved_state: &mut SavedStackingContextCollectionState,
stacking_relative_border_box: &Rect<Au>); stacking_relative_border_box: &Rect<Au>);
fn create_pseudo_stacking_context_for_block(&mut self, fn create_pseudo_stacking_context_for_block(
parent_stacking_context_id: StackingContextId, &mut self,
parent_clip_and_scroll_info: ClipAndScrollInfo, parent_stacking_context_id: StackingContextId,
state: &mut StackingContextCollectionState); parent_clip_and_scroll_info: ClippingAndScrolling,
fn create_real_stacking_context_for_block(&mut self, state: &mut StackingContextCollectionState
parent_stacking_context_id: StackingContextId, );
parent_clip_and_scroll_info: ClipAndScrollInfo, fn create_real_stacking_context_for_block(
state: &mut StackingContextCollectionState); &mut self,
parent_stacking_context_id: StackingContextId,
parent_clipping_and_scrolling: ClippingAndScrolling,
state: &mut StackingContextCollectionState
);
fn build_display_list_for_block(&mut self, fn build_display_list_for_block(&mut self,
state: &mut DisplayListBuildState, state: &mut DisplayListBuildState,
border_painting_mode: BorderPaintingMode); border_painting_mode: BorderPaintingMode);
@ -2454,8 +2470,8 @@ pub trait BlockFlowDisplayListBuilding {
pub struct SavedStackingContextCollectionState { pub struct SavedStackingContextCollectionState {
stacking_context_id: StackingContextId, stacking_context_id: StackingContextId,
real_stacking_context_id: StackingContextId, real_stacking_context_id: StackingContextId,
clip_and_scroll_info: ClipAndScrollInfo, clipping_and_scrolling: ClippingAndScrolling,
containing_block_clip_and_scroll_info: ClipAndScrollInfo, containing_block_clipping_and_scrolling: ClippingAndScrolling,
clips_pushed: usize, clips_pushed: usize,
containing_block_clips_pushed: usize, containing_block_clips_pushed: usize,
stacking_relative_content_box: Rect<Au>, stacking_relative_content_box: Rect<Au>,
@ -2466,8 +2482,8 @@ impl SavedStackingContextCollectionState {
SavedStackingContextCollectionState { SavedStackingContextCollectionState {
stacking_context_id: state.current_stacking_context_id, stacking_context_id: state.current_stacking_context_id,
real_stacking_context_id: state.current_real_stacking_context_id, real_stacking_context_id: state.current_real_stacking_context_id,
clip_and_scroll_info: state.current_clip_and_scroll_info, clipping_and_scrolling: state.current_clipping_and_scrolling,
containing_block_clip_and_scroll_info: state.containing_block_clip_and_scroll_info, containing_block_clipping_and_scrolling: state.containing_block_clipping_and_scrolling,
clips_pushed: 0, clips_pushed: 0,
containing_block_clips_pushed: 0, containing_block_clips_pushed: 0,
stacking_relative_content_box: state.parent_stacking_relative_content_box, stacking_relative_content_box: state.parent_stacking_relative_content_box,
@ -2483,8 +2499,8 @@ impl SavedStackingContextCollectionState {
fn restore(self, state: &mut StackingContextCollectionState) { fn restore(self, state: &mut StackingContextCollectionState) {
state.current_stacking_context_id = self.stacking_context_id; state.current_stacking_context_id = self.stacking_context_id;
state.current_real_stacking_context_id = self.real_stacking_context_id; state.current_real_stacking_context_id = self.real_stacking_context_id;
state.current_clip_and_scroll_info = self.clip_and_scroll_info; state.current_clipping_and_scrolling = self.clipping_and_scrolling;
state.containing_block_clip_and_scroll_info = self.containing_block_clip_and_scroll_info; state.containing_block_clipping_and_scrolling = self.containing_block_clipping_and_scrolling;
state.parent_stacking_relative_content_box = self.stacking_relative_content_box; state.parent_stacking_relative_content_box = self.stacking_relative_content_box;
let truncate_length = state.clip_stack.len() - self.clips_pushed; let truncate_length = state.clip_stack.len() - self.clips_pushed;
@ -2594,17 +2610,17 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
} }
// We are getting the id of the scroll root that contains us here, not the id of // We are getting the id of the scroll root that contains us here, not the id of
// any scroll root that we create. If we create a scroll root, its id will be // any scroll root that we create. If we create a scroll root, its index will be
// stored in state.current_clip_and_scroll_info. If we create a stacking context, // stored in state.current_clipping_and_scrolling. If we create a stacking context,
// we don't want it to be contained by its own scroll root. // we don't want it to be contained by its own scroll root.
let containing_clip_and_scroll_info = let containing_clipping_and_scrolling =
self.setup_clipping_for_block(state, self.setup_clipping_for_block(state,
&mut preserved_state, &mut preserved_state,
block_stacking_context_type, block_stacking_context_type,
flags); flags);
if establishes_containing_block_for_absolute(flags, self.positioning()) { if establishes_containing_block_for_absolute(flags, self.positioning()) {
state.containing_block_clip_and_scroll_info = state.current_clip_and_scroll_info; state.containing_block_clipping_and_scrolling = state.current_clipping_and_scrolling;
} }
match block_stacking_context_type { match block_stacking_context_type {
@ -2612,14 +2628,18 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
self.base.collect_stacking_contexts_for_children(state); self.base.collect_stacking_contexts_for_children(state);
} }
BlockStackingContextType::PseudoStackingContext => { BlockStackingContextType::PseudoStackingContext => {
self.create_pseudo_stacking_context_for_block(preserved_state.stacking_context_id, self.create_pseudo_stacking_context_for_block(
containing_clip_and_scroll_info, preserved_state.stacking_context_id,
state); containing_clipping_and_scrolling,
state
);
} }
BlockStackingContextType::StackingContext => { BlockStackingContextType::StackingContext => {
self.create_real_stacking_context_for_block(preserved_state.stacking_context_id, self.create_real_stacking_context_for_block(
containing_clip_and_scroll_info, preserved_state.stacking_context_id,
state); containing_clipping_and_scrolling,
state
);
} }
} }
@ -2631,22 +2651,22 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
preserved_state: &mut SavedStackingContextCollectionState, preserved_state: &mut SavedStackingContextCollectionState,
stacking_context_type: BlockStackingContextType, stacking_context_type: BlockStackingContextType,
flags: StackingContextCollectionFlags) flags: StackingContextCollectionFlags)
-> ClipAndScrollInfo { -> ClippingAndScrolling {
// If this block is absolutely positioned, we should be clipped and positioned by // If this block is absolutely positioned, we should be clipped and positioned by
// the scroll root of our nearest ancestor that establishes a containing block. // the scroll root of our nearest ancestor that establishes a containing block.
let containing_clip_and_scroll_info = match self.positioning() { let containing_clipping_and_scrolling = match self.positioning() {
position::T::absolute => { position::T::absolute => {
preserved_state.switch_to_containing_block_clip(state); preserved_state.switch_to_containing_block_clip(state);
state.current_clip_and_scroll_info = state.containing_block_clip_and_scroll_info; state.current_clipping_and_scrolling = state.containing_block_clipping_and_scrolling;
state.containing_block_clip_and_scroll_info state.containing_block_clipping_and_scrolling
} }
position::T::fixed => { position::T::fixed => {
preserved_state.push_clip(state, &max_rect(), position::T::fixed); preserved_state.push_clip(state, &max_rect(), position::T::fixed);
state.current_clip_and_scroll_info state.current_clipping_and_scrolling
} }
_ => state.current_clip_and_scroll_info, _ => state.current_clipping_and_scrolling,
}; };
self.base.clip_and_scroll_info = Some(containing_clip_and_scroll_info); self.base.clipping_and_scrolling = Some(containing_clipping_and_scrolling);
let stacking_relative_border_box = if self.fragment.establishes_stacking_context() { let stacking_relative_border_box = if self.fragment.establishes_stacking_context() {
self.stacking_relative_border_box(CoordinateSystem::Own) self.stacking_relative_border_box(CoordinateSystem::Own)
@ -2680,11 +2700,11 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
match self.positioning() { match self.positioning() {
position::T::absolute | position::T::relative | position::T::fixed => position::T::absolute | position::T::relative | position::T::fixed =>
state.containing_block_clip_and_scroll_info = state.current_clip_and_scroll_info, state.containing_block_clipping_and_scrolling = state.current_clipping_and_scrolling,
_ => {} _ => {}
} }
containing_clip_and_scroll_info containing_clipping_and_scrolling
} }
fn setup_clip_scroll_node_for_position(&mut self, fn setup_clip_scroll_node_for_position(&mut self,
@ -2735,25 +2755,19 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
to_sticky_info(sticky_position.left, to_sticky_info(sticky_position.left,
to_max_offset(constraint_rect.max_x(), border_box_in_parent.max_x()))); to_max_offset(constraint_rect.max_x(), border_box_in_parent.max_x())));
let new_clip_scroll_node_id = ClipId::new(self.fragment.unique_id(IdType::OverflowClip), let new_clip_scroll_index = state.add_clip_scroll_node(
state.pipeline_id.to_webrender());
if state.has_clip_scroll_node(new_clip_scroll_node_id) {
return;
}
let parent_id = self.clip_and_scroll_info(state.pipeline_id).scroll_node_id;
state.add_clip_scroll_node(
ClipScrollNode { ClipScrollNode {
id: new_clip_scroll_node_id, id: None,
parent_id: parent_id, parent_index: self.clipping_and_scrolling().scrolling,
clip: ClippingRegion::from_rect(border_box), clip: ClippingRegion::from_rect(border_box),
content_rect: Rect::zero(), content_rect: Rect::zero(),
node_type: ClipScrollNodeType::StickyFrame(sticky_frame_info), node_type: ClipScrollNodeType::StickyFrame(sticky_frame_info),
}, },
); );
let new_clip_and_scroll_info = ClipAndScrollInfo::simple(new_clip_scroll_node_id); let new_clipping_and_scrolling = ClippingAndScrolling::simple(new_clip_scroll_index);
self.base.clip_and_scroll_info = Some(new_clip_and_scroll_info); self.base.clipping_and_scrolling = Some(new_clipping_and_scrolling);
state.current_clip_and_scroll_info = new_clip_and_scroll_info; state.current_clipping_and_scrolling = new_clipping_and_scrolling;
} }
fn setup_clip_scroll_node_for_overflow(&mut self, fn setup_clip_scroll_node_for_overflow(&mut self,
@ -2781,9 +2795,6 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
// wrappers. We just accept the first scroll root in that case. // wrappers. We just accept the first scroll root in that case.
let new_clip_scroll_node_id = ClipId::new(self.fragment.unique_id(IdType::OverflowClip), let new_clip_scroll_node_id = ClipId::new(self.fragment.unique_id(IdType::OverflowClip),
state.pipeline_id.to_webrender()); state.pipeline_id.to_webrender());
if state.has_clip_scroll_node(new_clip_scroll_node_id) {
return;
}
let sensitivity = if overflow_x::T::hidden == self.fragment.style.get_box().overflow_x && let sensitivity = if overflow_x::T::hidden == self.fragment.style.get_box().overflow_x &&
overflow_x::T::hidden == self.fragment.style.get_box().overflow_y { overflow_x::T::hidden == self.fragment.style.get_box().overflow_y {
@ -2802,20 +2813,19 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
let content_size = self.base.overflow.scroll.origin + self.base.overflow.scroll.size; let content_size = self.base.overflow.scroll.origin + self.base.overflow.scroll.size;
let content_size = Size2D::new(content_size.x, content_size.y); let content_size = Size2D::new(content_size.x, content_size.y);
let parent_id = self.clip_and_scroll_info(state.pipeline_id).scroll_node_id; let new_clip_scroll_index = state.add_clip_scroll_node(
state.add_clip_scroll_node(
ClipScrollNode { ClipScrollNode {
id: new_clip_scroll_node_id, id: Some(new_clip_scroll_node_id),
parent_id: parent_id, parent_index: self.clipping_and_scrolling().scrolling,
clip: clip, clip: clip,
content_rect: Rect::new(content_box.origin, content_size), content_rect: Rect::new(content_box.origin, content_size),
node_type: ClipScrollNodeType::ScrollFrame(sensitivity), node_type: ClipScrollNodeType::ScrollFrame(sensitivity),
}, },
); );
let new_clip_and_scroll_info = ClipAndScrollInfo::simple(new_clip_scroll_node_id); let new_clipping_and_scrolling = ClippingAndScrolling::simple(new_clip_scroll_index);
self.base.clip_and_scroll_info = Some(new_clip_and_scroll_info); self.base.clipping_and_scrolling = Some(new_clipping_and_scrolling);
state.current_clip_and_scroll_info = new_clip_and_scroll_info; state.current_clipping_and_scrolling = new_clipping_and_scrolling;
} }
/// Adds a scroll root for a block to take the `clip` property into account /// Adds a scroll root for a block to take the `clip` property into account
@ -2847,44 +2857,30 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
.unwrap_or(stacking_relative_border_box.size.height); .unwrap_or(stacking_relative_border_box.size.height);
let clip_size = Size2D::new(right - clip_origin.x, bottom - clip_origin.y); let clip_size = Size2D::new(right - clip_origin.x, bottom - clip_origin.y);
// We use the node id to create scroll roots for overflow properties, so we
// use the fragment address to do the same for CSS clipping.
// TODO(mrobinson): This should be more resilient while maintaining the space
// efficiency of ClipScrollNode.
let new_clip_scroll_node_id = ClipId::new(self.fragment.unique_id(IdType::CSSClip),
state.pipeline_id.to_webrender());
// If we already have a scroll root for this flow, just return. This can happen
// when fragments map to more than one flow, such as in the case of table
// wrappers. We just accept the first scroll root in that case.
if state.has_clip_scroll_node(new_clip_scroll_node_id) {
return;
}
let clip_rect = Rect::new(clip_origin, clip_size); let clip_rect = Rect::new(clip_origin, clip_size);
preserved_state.push_clip(state, &clip_rect, self.positioning()); preserved_state.push_clip(state, &clip_rect, self.positioning());
let parent_id = self.clip_and_scroll_info(state.pipeline_id).scroll_node_id; let new_index = state.add_clip_scroll_node(
state.add_clip_scroll_node(
ClipScrollNode { ClipScrollNode {
id: new_clip_scroll_node_id, id: None,
parent_id: parent_id, parent_index: self.clipping_and_scrolling().scrolling,
clip: ClippingRegion::from_rect(&clip_rect), clip: ClippingRegion::from_rect(&clip_rect),
content_rect: Rect::zero(), // content_rect isn't important for clips. content_rect: Rect::zero(), // content_rect isn't important for clips.
node_type: ClipScrollNodeType::Clip, node_type: ClipScrollNodeType::Clip,
}, },
); );
let new_clip_and_scroll_info = ClipAndScrollInfo::new(new_clip_scroll_node_id, let new_indices = ClippingAndScrolling::new(new_index, new_index);
new_clip_scroll_node_id); self.base.clipping_and_scrolling = Some(new_indices);
self.base.clip_and_scroll_info = Some(new_clip_and_scroll_info); state.current_clipping_and_scrolling = new_indices;
state.current_clip_and_scroll_info = new_clip_and_scroll_info;
} }
fn create_pseudo_stacking_context_for_block(&mut self, fn create_pseudo_stacking_context_for_block(
parent_stacking_context_id: StackingContextId, &mut self,
parent_clip_and_scroll_info: ClipAndScrollInfo, parent_stacking_context_id: StackingContextId,
state: &mut StackingContextCollectionState) { parent_clipping_and_scrolling: ClippingAndScrolling,
state: &mut StackingContextCollectionState
) {
let creation_mode = if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) || let creation_mode = if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) ||
self.fragment.style.get_box().position != position::T::static_ { self.fragment.style.get_box().position != position::T::static_ {
StackingContextType::PseudoPositioned StackingContextType::PseudoPositioned
@ -2897,7 +2893,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
&self.base, &self.base,
ScrollPolicy::Scrollable, ScrollPolicy::Scrollable,
creation_mode, creation_mode,
parent_clip_and_scroll_info); parent_clipping_and_scrolling);
state.add_stacking_context(parent_stacking_context_id, new_context); state.add_stacking_context(parent_stacking_context_id, new_context);
self.base.collect_stacking_contexts_for_children(state); self.base.collect_stacking_contexts_for_children(state);
@ -2915,10 +2911,12 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
} }
} }
fn create_real_stacking_context_for_block(&mut self, fn create_real_stacking_context_for_block(
parent_stacking_context_id: StackingContextId, &mut self,
parent_clip_and_scroll_info: ClipAndScrollInfo, parent_stacking_context_id: StackingContextId,
state: &mut StackingContextCollectionState) { parent_clipping_and_scrolling: ClippingAndScrolling,
state: &mut StackingContextCollectionState
) {
let scroll_policy = if self.is_fixed() { let scroll_policy = if self.is_fixed() {
ScrollPolicy::Fixed ScrollPolicy::Fixed
} else { } else {
@ -2930,7 +2928,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
&self.base, &self.base,
scroll_policy, scroll_policy,
StackingContextType::Real, StackingContextType::Real,
parent_clip_and_scroll_info); parent_clipping_and_scrolling
);
state.add_stacking_context(parent_stacking_context_id, stacking_context); state.add_stacking_context(parent_stacking_context_id, stacking_context);
self.base.collect_stacking_contexts_for_children(state); self.base.collect_stacking_contexts_for_children(state);
@ -3012,14 +3011,14 @@ pub trait InlineFlowDisplayListBuilding {
impl InlineFlowDisplayListBuilding for InlineFlow { impl InlineFlowDisplayListBuilding for InlineFlow {
fn collect_stacking_contexts_for_inline(&mut self, state: &mut StackingContextCollectionState) { fn collect_stacking_contexts_for_inline(&mut self, state: &mut StackingContextCollectionState) {
self.base.stacking_context_id = state.current_stacking_context_id; self.base.stacking_context_id = state.current_stacking_context_id;
self.base.clip_and_scroll_info = Some(state.current_clip_and_scroll_info); self.base.clipping_and_scrolling = Some(state.current_clipping_and_scrolling);
self.base.clip = state.clip_stack.last().cloned().unwrap_or_else(max_rect); self.base.clip = state.clip_stack.last().cloned().unwrap_or_else(max_rect);
for fragment in self.fragments.fragments.iter_mut() { for fragment in self.fragments.fragments.iter_mut() {
let previous_cb_clip_scroll_info = state.containing_block_clip_and_scroll_info; let previous_cb_clipping_and_scrolling = state.containing_block_clipping_and_scrolling;
if establishes_containing_block_for_absolute(StackingContextCollectionFlags::empty(), if establishes_containing_block_for_absolute(StackingContextCollectionFlags::empty(),
fragment.style.get_box().position) { fragment.style.get_box().position) {
state.containing_block_clip_and_scroll_info = state.current_clip_and_scroll_info; state.containing_block_clipping_and_scrolling = state.current_clipping_and_scrolling;
} }
if !fragment.collect_stacking_contexts_for_blocklike_fragment(state) { if !fragment.collect_stacking_contexts_for_blocklike_fragment(state) {
@ -3027,12 +3026,13 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
fragment.stacking_context_id = state.generate_stacking_context_id(); fragment.stacking_context_id = state.generate_stacking_context_id();
let current_stacking_context_id = state.current_stacking_context_id; let current_stacking_context_id = state.current_stacking_context_id;
let stacking_context = let stacking_context = fragment.create_stacking_context(
fragment.create_stacking_context(fragment.stacking_context_id, fragment.stacking_context_id,
&self.base, &self.base,
ScrollPolicy::Scrollable, ScrollPolicy::Scrollable,
StackingContextType::Real, StackingContextType::Real,
state.current_clip_and_scroll_info); state.current_clipping_and_scrolling
);
state.add_stacking_context(current_stacking_context_id, stacking_context); state.add_stacking_context(current_stacking_context_id, stacking_context);
} else { } else {
@ -3040,7 +3040,7 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
} }
} }
state.containing_block_clip_and_scroll_info = previous_cb_clip_scroll_info; state.containing_block_clipping_and_scrolling = previous_cb_clipping_and_scrolling;
} }
} }

View file

@ -35,11 +35,11 @@ use floats::{Floats, SpeculatedFloatPlacement};
use flow_list::{FlowList, FlowListIterator, MutFlowListIterator}; use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
use flow_ref::{FlowRef, WeakFlowRef}; use flow_ref::{FlowRef, WeakFlowRef};
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, Overflow}; use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, Overflow};
use gfx::display_list::ClippingAndScrolling;
use gfx_traits::StackingContextId; use gfx_traits::StackingContextId;
use gfx_traits::print_tree::PrintTree; use gfx_traits::print_tree::PrintTree;
use inline::InlineFlow; use inline::InlineFlow;
use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo}; use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo};
use msg::constellation_msg::PipelineId;
use multicol::MulticolFlow; use multicol::MulticolFlow;
use parallel::FlowParallelInfo; use parallel::FlowParallelInfo;
use serde::ser::{Serialize, SerializeStruct, Serializer}; use serde::ser::{Serialize, SerializeStruct, Serializer};
@ -63,7 +63,6 @@ use table_colgroup::TableColGroupFlow;
use table_row::TableRowFlow; use table_row::TableRowFlow;
use table_rowgroup::TableRowGroupFlow; use table_rowgroup::TableRowGroupFlow;
use table_wrapper::TableWrapperFlow; use table_wrapper::TableWrapperFlow;
use webrender_api::ClipAndScrollInfo;
/// This marker trait indicates that a type is a struct with `#[repr(C)]` whose first field /// This marker trait indicates that a type is a struct with `#[repr(C)]` whose first field
/// is of type `BaseFlow` or some type that also implements this trait. /// is of type `BaseFlow` or some type that also implements this trait.
@ -444,13 +443,10 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static {
/// children of this flow. /// children of this flow.
fn print_extra_flow_children(&self, _: &mut PrintTree) { } fn print_extra_flow_children(&self, _: &mut PrintTree) { }
fn clip_and_scroll_info(&self, pipeline_id: PipelineId) -> ClipAndScrollInfo { fn clipping_and_scrolling(&self) -> ClippingAndScrolling {
match base(self).clip_and_scroll_info { match base(self).clipping_and_scrolling {
Some(info) => info, Some(info) => info,
None => { None => unreachable!("Tried to access scroll root id on Flow before assignment"),
debug_assert!(false, "Tried to access scroll root id on Flow before assignment");
pipeline_id.root_clip_and_scroll_info()
}
} }
} }
} }
@ -920,7 +916,9 @@ pub struct BaseFlow {
/// list construction. /// list construction.
pub stacking_context_id: StackingContextId, pub stacking_context_id: StackingContextId,
pub clip_and_scroll_info: Option<ClipAndScrollInfo>, /// The indices of this Flow's ClipScrollNode. This is used to place the node's
/// display items into scrolling frames and clipping nodes.
pub clipping_and_scrolling: Option<ClippingAndScrolling>,
} }
impl fmt::Debug for BaseFlow { impl fmt::Debug for BaseFlow {
@ -1062,7 +1060,7 @@ impl BaseFlow {
writing_mode: writing_mode, writing_mode: writing_mode,
thread_id: 0, thread_id: 0,
stacking_context_id: StackingContextId::root(), stacking_context_id: StackingContextId::root(),
clip_and_scroll_info: None, clipping_and_scrolling: None,
} }
} }

View file

@ -98,7 +98,7 @@ impl Flow for TableColGroupFlow {
fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) { fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) {
self.base.stacking_context_id = state.current_stacking_context_id; self.base.stacking_context_id = state.current_stacking_context_id;
self.base.clip_and_scroll_info = Some(state.current_clip_and_scroll_info); self.base.clipping_and_scrolling = Some(state.current_clipping_and_scrolling);
} }
fn repair_style(&mut self, _: &::ServoArc<ComputedValues>) {} fn repair_style(&mut self, _: &::ServoArc<ComputedValues>) {}

View file

@ -313,9 +313,8 @@ impl<'a> BuildDisplayList<'a> {
let parent_stacking_context_id = self.state.current_stacking_context_id; let parent_stacking_context_id = self.state.current_stacking_context_id;
self.state.current_stacking_context_id = flow::base(flow).stacking_context_id; self.state.current_stacking_context_id = flow::base(flow).stacking_context_id;
let parent_clip_and_scroll_info = self.state.current_clip_and_scroll_info; let parent_clipping_and_scrolling = self.state.current_clipping_and_scrolling;
self.state.current_clip_and_scroll_info = self.state.current_clipping_and_scrolling = flow.clipping_and_scrolling();
flow.clip_and_scroll_info(self.state.layout_context.id);
flow.build_display_list(&mut self.state); flow.build_display_list(&mut self.state);
flow::mut_base(flow).restyle_damage.remove(REPAINT); flow::mut_base(flow).restyle_damage.remove(REPAINT);
@ -325,6 +324,6 @@ impl<'a> BuildDisplayList<'a> {
} }
self.state.current_stacking_context_id = parent_stacking_context_id; self.state.current_stacking_context_id = parent_stacking_context_id;
self.state.current_clip_and_scroll_info = parent_clip_and_scroll_info; self.state.current_clipping_and_scrolling = parent_clipping_and_scrolling;
} }
} }

View file

@ -9,14 +9,15 @@
use app_units::Au; use app_units::Au;
use euclid::{Point2D, Vector2D, Rect, SideOffsets2D, Size2D}; use euclid::{Point2D, Vector2D, Rect, SideOffsets2D, Size2D};
use gfx::display_list::{BorderDetails, BorderRadii, BoxShadowClipMode, ClipScrollNodeType}; use gfx::display_list::{BorderDetails, BorderRadii, BoxShadowClipMode, ClipScrollNode};
use gfx::display_list::{ClippingRegion, DisplayItem, DisplayList, StackingContextType}; use gfx::display_list::{ClipScrollNodeIndex, ClipScrollNodeType, ClippingRegion, DisplayItem};
use gfx::display_list::{DisplayList, StackingContextType};
use msg::constellation_msg::PipelineId; use msg::constellation_msg::PipelineId;
use style::computed_values::{image_rendering, mix_blend_mode, transform_style}; use style::computed_values::{image_rendering, mix_blend_mode, transform_style};
use style::values::computed::{BorderStyle, Filter}; use style::values::computed::{BorderStyle, Filter};
use style::values::generics::effects::Filter as GenericFilter; use style::values::generics::effects::Filter as GenericFilter;
use webrender_api::{self, ClipAndScrollInfo, ComplexClipRegion, DisplayListBuilder}; use webrender_api::{self, ClipAndScrollInfo, ClipId, ClipMode, ComplexClipRegion};
use webrender_api::{ClipMode, ExtendMode, LayoutTransform}; use webrender_api::{DisplayListBuilder, ExtendMode, LayoutTransform};
pub trait WebRenderDisplayListConverter { pub trait WebRenderDisplayListConverter {
fn convert_to_webrender(&self, pipeline_id: PipelineId) -> DisplayListBuilder; fn convert_to_webrender(&self, pipeline_id: PipelineId) -> DisplayListBuilder;
@ -24,9 +25,13 @@ pub trait WebRenderDisplayListConverter {
trait WebRenderDisplayItemConverter { trait WebRenderDisplayItemConverter {
fn prim_info(&self) -> webrender_api::LayoutPrimitiveInfo; fn prim_info(&self) -> webrender_api::LayoutPrimitiveInfo;
fn convert_to_webrender(&self, fn convert_to_webrender(
builder: &mut DisplayListBuilder, &self,
current_clip_and_scroll_info: &mut ClipAndScrollInfo); builder: &mut DisplayListBuilder,
clip_scroll_nodes: &[ClipScrollNode],
clip_ids: &mut Vec<Option<ClipId>>,
current_clip_and_scroll_info: &mut ClipAndScrollInfo
);
} }
trait ToBorderStyle { trait ToBorderStyle {
@ -227,8 +232,17 @@ impl WebRenderDisplayListConverter for DisplayList {
let mut current_clip_and_scroll_info = pipeline_id.root_clip_and_scroll_info(); let mut current_clip_and_scroll_info = pipeline_id.root_clip_and_scroll_info();
builder.push_clip_and_scroll_info(current_clip_and_scroll_info); builder.push_clip_and_scroll_info(current_clip_and_scroll_info);
let mut clip_ids = Vec::with_capacity(self.clip_scroll_nodes.len());
clip_ids.resize(self.clip_scroll_nodes.len(), None);
clip_ids[0] = Some(ClipId::root_scroll_node(pipeline_id.to_webrender()));
for item in &self.list { for item in &self.list {
item.convert_to_webrender(&mut builder, &mut current_clip_and_scroll_info); item.convert_to_webrender(
&mut builder,
&self.clip_scroll_nodes,
&mut clip_ids,
&mut current_clip_and_scroll_info
);
} }
builder builder
} }
@ -249,10 +263,27 @@ impl WebRenderDisplayItemConverter for DisplayItem {
} }
} }
fn convert_to_webrender(&self, fn convert_to_webrender(
builder: &mut DisplayListBuilder, &self,
current_clip_and_scroll_info: &mut ClipAndScrollInfo) { builder: &mut DisplayListBuilder,
let clip_and_scroll_info = self.base().clip_and_scroll_info; clip_scroll_nodes: &[ClipScrollNode],
clip_ids: &mut Vec<Option<ClipId>>,
current_clip_and_scroll_info: &mut ClipAndScrollInfo
) {
let get_id = |clip_ids: &[Option<ClipId>], index: ClipScrollNodeIndex| -> ClipId {
match clip_ids[index.0] {
Some(id) => id,
None => unreachable!("Tried to use WebRender ClipId before it was defined."),
}
};
let clip_and_scroll_indices = self.base().clipping_and_scrolling;
let scrolling_id = get_id(clip_ids, clip_and_scroll_indices.scrolling);
let clip_and_scroll_info = match clip_and_scroll_indices.clipping {
None => ClipAndScrollInfo::simple(scrolling_id),
Some(index) => ClipAndScrollInfo::new(scrolling_id, get_id(clip_ids, index)),
};
if clip_and_scroll_info != *current_clip_and_scroll_info { if clip_and_scroll_info != *current_clip_and_scroll_info {
builder.pop_clip_id(); builder.pop_clip_id();
builder.push_clip_and_scroll_info(clip_and_scroll_info); builder.push_clip_and_scroll_info(clip_and_scroll_info);
@ -487,32 +518,42 @@ impl WebRenderDisplayItemConverter for DisplayItem {
} }
DisplayItem::PopStackingContext(_) => builder.pop_stacking_context(), DisplayItem::PopStackingContext(_) => builder.pop_stacking_context(),
DisplayItem::DefineClipScrollNode(ref item) => { DisplayItem::DefineClipScrollNode(ref item) => {
builder.push_clip_id(item.node.parent_id); let node = &clip_scroll_nodes[item.node_index.0];
let parent_id = get_id(clip_ids, node.parent_index);
let item_rect = node.clip.main.to_rectf();
let our_id = item.node.id; let webrender_id = match node.node_type {
let item_rect = item.node.clip.main.to_rectf();
let webrender_id = match item.node.node_type {
ClipScrollNodeType::Clip => { ClipScrollNodeType::Clip => {
builder.define_clip(Some(our_id), builder.define_clip_with_parent(
item_rect, node.id,
item.node.clip.get_complex_clips(), parent_id,
None) item_rect,
node.clip.get_complex_clips(),
None
)
} }
ClipScrollNodeType::ScrollFrame(scroll_sensitivity) => { ClipScrollNodeType::ScrollFrame(scroll_sensitivity) => {
builder.define_scroll_frame(Some(our_id), builder.define_scroll_frame_with_parent(
item.node.content_rect.to_rectf(), node.id,
item.node.clip.main.to_rectf(), parent_id,
item.node.clip.get_complex_clips(), node.content_rect.to_rectf(),
None, node.clip.main.to_rectf(),
scroll_sensitivity) node.clip.get_complex_clips(),
None,
scroll_sensitivity
)
} }
ClipScrollNodeType::StickyFrame(sticky_frame_info) => { ClipScrollNodeType::StickyFrame(sticky_frame_info) => {
builder.define_sticky_frame(Some(our_id), item_rect, sticky_frame_info) // TODO: Add define_sticky_frame_with_parent to WebRender.
builder.push_clip_id(parent_id);
let id = builder.define_sticky_frame(node.id, item_rect, sticky_frame_info);
builder.pop_clip_id();
id
} }
}; };
debug_assert!(our_id == webrender_id);
builder.pop_clip_id(); debug_assert!(node.id.is_none() || node.id == Some(webrender_id));
clip_ids[item.node_index.0] = Some(webrender_id);
} }
} }
} }

View file

@ -189,6 +189,11 @@ svg > * {
position: static; position: static;
margin: 0; margin: 0;
counter-increment: none; counter-increment: none;
/* We don't want anonymous table parts to inherit hidden overflow, because
* they will create extra unnecessary ClipScrollNodes which also throws
* off assignment of contained flows. */
overflow: visible;
} }
*|*::-servo-anonymous-table { *|*::-servo-anonymous-table {
@ -197,6 +202,7 @@ svg > * {
border: none; border: none;
padding: 0; padding: 0;
counter-increment: none; counter-increment: none;
overflow: visible;
} }
*|*::-servo-anonymous-table-row { *|*::-servo-anonymous-table-row {
@ -204,6 +210,7 @@ svg > * {
position: static; position: static;
border: none; border: none;
counter-increment: none; counter-increment: none;
overflow: visible;
} }
*|*::-servo-anonymous-table-cell { *|*::-servo-anonymous-table-cell {
@ -211,6 +218,7 @@ svg > * {
position: static; position: static;
border: none; border: none;
counter-increment: none; counter-increment: none;
overflow: visible;
} }
*|*::-servo-anonymous-block { *|*::-servo-anonymous-block {

View file

@ -61,7 +61,8 @@ fn test_common(display_list: &DisplayList, epoch: Epoch) -> PaintTimeMetrics {
#[test] #[test]
fn test_first_paint_setter() { fn test_first_paint_setter() {
let empty_display_list = DisplayList { let empty_display_list = DisplayList {
list: Vec::new() list: Vec::new(),
clip_scroll_nodes: Vec::new(),
}; };
let epoch = Epoch(0); let epoch = Epoch(0);
let mut paint_time_metrics = test_common(&empty_display_list, epoch); let mut paint_time_metrics = test_common(&empty_display_list, epoch);
@ -74,7 +75,7 @@ fn test_first_paint_setter() {
#[test] #[test]
fn test_first_contentful_paint_setter() { fn test_first_contentful_paint_setter() {
let image = DisplayItem::Image(Box::new(ImageDisplayItem { let image = DisplayItem::Image(Box::new(ImageDisplayItem {
base: BaseDisplayItem::empty(TEST_PIPELINE_ID), base: BaseDisplayItem::empty(),
webrender_image: WebRenderImageInfo { webrender_image: WebRenderImageInfo {
width: 1, width: 1,
height: 1, height: 1,
@ -87,7 +88,8 @@ fn test_first_contentful_paint_setter() {
image_rendering: image_rendering::T::auto, image_rendering: image_rendering::T::auto,
})); }));
let display_list = DisplayList { let display_list = DisplayList {
list: vec![image] list: vec![image],
clip_scroll_nodes: Vec::new(),
}; };
let epoch = Epoch(0); let epoch = Epoch(0);
let mut paint_time_metrics = test_common(&display_list, epoch); let mut paint_time_metrics = test_common(&display_list, epoch);