diff options
-rw-r--r-- | components/gfx/display_list/mod.rs | 159 | ||||
-rw-r--r-- | components/layout/display_list_builder.rs | 338 | ||||
-rw-r--r-- | components/layout/flow.rs | 18 | ||||
-rw-r--r-- | components/layout/table_colgroup.rs | 2 | ||||
-rw-r--r-- | components/layout/traversal.rs | 7 | ||||
-rw-r--r-- | components/layout/webrender_helpers.rs | 99 | ||||
-rw-r--r-- | resources/servo.css | 8 | ||||
-rw-r--r-- | tests/unit/metrics/paint_time.rs | 8 |
8 files changed, 365 insertions, 274 deletions
diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index 3d7343435dc..30d683d6cc0 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -33,9 +33,8 @@ use style::values::computed::Filter; use style_traits::cursor::Cursor; use text::TextRun; use text::glyph::ByteIndex; -use webrender_api::{self, ClipAndScrollInfo, ClipId, ColorF, GradientStop, LocalClip}; -use webrender_api::{MixBlendMode, ScrollPolicy, ScrollSensitivity, StickyFrameInfo}; -use webrender_api::TransformStyle; +use webrender_api::{self, ClipId, ColorF, GradientStop, LocalClip, MixBlendMode, ScrollPolicy}; +use webrender_api::{ScrollSensitivity, StickyFrameInfo, TransformStyle}; 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. 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)] pub struct DisplayList { pub list: Vec<DisplayItem>, + pub clip_scroll_nodes: Vec<ClipScrollNode>, } impl DisplayList { @@ -84,12 +128,19 @@ impl DisplayList { } 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()); for item in &self.list { print_tree.add_item(format!("{:?} StackingContext: {:?} {:?}", - item, - item.base().stacking_context_id, - item.clip_and_scroll_info())); + item, + item.base().stacking_context_id, + item.clipping_and_scrolling()) + ); } print_tree.end_level(); } @@ -150,7 +201,7 @@ pub struct StackingContext { pub scroll_policy: ScrollPolicy, /// The clip and scroll info for this StackingContext. - pub parent_clip_and_scroll_info: ClipAndScrollInfo, + pub parent_clipping_and_scrolling: ClippingAndScrolling, } impl StackingContext { @@ -167,44 +218,46 @@ impl StackingContext { transform_style: TransformStyle, perspective: Option<Transform3D<f32>>, scroll_policy: ScrollPolicy, - parent_clip_and_scroll_info: ClipAndScrollInfo) + parent_clipping_and_scrolling: ClippingAndScrolling) -> StackingContext { StackingContext { - id: id, - context_type: context_type, + id, + context_type, bounds: *bounds, overflow: *overflow, - z_index: z_index, - filters: filters, - mix_blend_mode: mix_blend_mode, - transform: transform, - transform_style: transform_style, - perspective: perspective, - scroll_policy: scroll_policy, - parent_clip_and_scroll_info: parent_clip_and_scroll_info, + z_index, + filters, + mix_blend_mode, + transform, + transform_style, + perspective, + scroll_policy, + parent_clipping_and_scrolling, } } #[inline] - pub fn root(pipeline_id: PipelineId) -> StackingContext { - StackingContext::new(StackingContextId::root(), - StackingContextType::Real, - &Rect::zero(), - &Rect::zero(), - 0, - vec![], - MixBlendMode::Normal, - None, - TransformStyle::Flat, - None, - ScrollPolicy::Scrollable, - pipeline_id.root_clip_and_scroll_info()) + pub fn root() -> StackingContext { + StackingContext::new( + StackingContextId::root(), + StackingContextType::Real, + &Rect::zero(), + &Rect::zero(), + 0, + vec![], + MixBlendMode::Normal, + None, + TransformStyle::Flat, + None, + ScrollPolicy::Scrollable, + ClippingAndScrolling::simple(ClipScrollNodeIndex(0)) + ) } - pub fn to_display_list_items(self, pipeline_id: PipelineId) -> (DisplayItem, DisplayItem) { - let mut base_item = BaseDisplayItem::empty(pipeline_id); + pub fn to_display_list_items(self) -> (DisplayItem, DisplayItem) { + let mut base_item = BaseDisplayItem::empty(); 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( PopStackingContextItem { @@ -280,10 +333,10 @@ pub enum ClipScrollNodeType { pub struct ClipScrollNode { /// The WebRender clip id of this scroll root based on the source of this clip /// and information about the fragment. - pub id: ClipId, + pub id: Option<ClipId>, - /// The unique ID of the parent of this ClipScrollNode. - pub parent_id: ClipId, + /// The index of the parent of this ClipScrollNode. + pub parent_index: ClipScrollNodeIndex, /// The position of this scroll root's frame in the parent stacking context. pub clip: ClippingRegion, @@ -295,16 +348,6 @@ pub struct ClipScrollNode { 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. #[derive(Clone, Deserialize, MallocSizeOf, Serialize)] pub enum DisplayItem { @@ -343,7 +386,7 @@ pub struct BaseDisplayItem { pub stacking_context_id: StackingContextId, /// The clip and scroll info for this item. - pub clip_and_scroll_info: ClipAndScrollInfo, + pub clipping_and_scrolling: ClippingAndScrolling, } impl BaseDisplayItem { @@ -353,7 +396,7 @@ impl BaseDisplayItem { local_clip: LocalClip, section: DisplayListSection, stacking_context_id: StackingContextId, - clip_and_scroll_info: ClipAndScrollInfo) + clipping_and_scrolling: ClippingAndScrolling) -> BaseDisplayItem { BaseDisplayItem { bounds: *bounds, @@ -361,12 +404,12 @@ impl BaseDisplayItem { local_clip: local_clip, section: section, stacking_context_id: stacking_context_id, - clip_and_scroll_info: clip_and_scroll_info, + clipping_and_scrolling: clipping_and_scrolling, } } #[inline(always)] - pub fn empty(pipeline_id: PipelineId) -> BaseDisplayItem { + pub fn empty() -> BaseDisplayItem { BaseDisplayItem { bounds: TypedRect::zero(), metadata: DisplayItemMetadata { @@ -376,7 +419,7 @@ impl BaseDisplayItem { local_clip: LocalClip::from(max_rect().to_rectf()), section: DisplayListSection::Content, 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, /// The scroll root that this item starts. - pub node: ClipScrollNode, + pub node_index: ClipScrollNodeIndex, } /// How a box shadow should be clipped. @@ -963,12 +1006,12 @@ impl DisplayItem { } } - pub fn scroll_node_id(&self) -> ClipId { - self.base().clip_and_scroll_info.scroll_node_id + pub fn scroll_node_index(&self) -> ClipScrollNodeIndex { + self.base().clipping_and_scrolling.scrolling } - pub fn clip_and_scroll_info(&self) -> ClipAndScrollInfo { - self.base().clip_and_scroll_info + pub fn clipping_and_scrolling(&self) -> ClippingAndScrolling { + self.base().clipping_and_scrolling } pub fn stacking_context_id(&self) -> StackingContextId { @@ -1003,7 +1046,7 @@ impl fmt::Debug for DisplayItem { } if let DisplayItem::DefineClipScrollNode(ref item) = *self { - return write!(f, "DefineClipScrollNode({:?}", item.node); + return write!(f, "DefineClipScrollNode({:?}", item.node_index); } write!(f, "{} @ {:?} {:?}", diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 4baa85f95b4..f9c87127c95 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -14,8 +14,7 @@ use app_units::{AU_PER_PX, Au}; use block::{BlockFlow, BlockStackingContextType}; use canvas_traits::canvas::{CanvasMsg, FromLayoutMsg}; use context::LayoutContext; -use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Transform3D, TypedSize2D}; -use euclid::Vector2D; +use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Transform3D, TypedRect, TypedSize2D, Vector2D}; use flex::FlexFlow; use flow::{BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED}; use flow_ref::FlowRef; @@ -25,9 +24,10 @@ use fragment::SpecificFragmentInfo; use gfx::display_list; use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDetails, BorderDisplayItem}; use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClipScrollNode}; -use gfx::display_list::{ClipScrollNodeType, ClippingRegion, DisplayItem, DisplayItemMetadata}; -use gfx::display_list::{DisplayList, DisplayListSection, GradientDisplayItem, IframeDisplayItem}; -use gfx::display_list::{ImageBorder, ImageDisplayItem, LineDisplayItem, NormalBorder, OpaqueNode}; +use gfx::display_list::{ClipScrollNodeIndex, ClippingAndScrolling, ClipScrollNodeType}; +use gfx::display_list::{ClippingRegion, DisplayItem, DisplayItemMetadata, DisplayList}; +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::{RadialGradientDisplayItem, SolidColorDisplayItem, StackingContext}; use gfx::display_list::{StackingContextType, TextDisplayItem, TextOrientation, WebRenderImageInfo}; @@ -71,8 +71,8 @@ use style_traits::CSSPixel; use style_traits::ToCss; use style_traits::cursor::Cursor; use table_cell::CollapsedBordersForCell; -use webrender_api::{ClipAndScrollInfo, ClipId, ClipMode, ColorF, ComplexClipRegion, GradientStop}; -use webrender_api::{LineStyle, LocalClip, RepeatMode, ScrollPolicy, ScrollSensitivity, StickyFrameInfo}; +use webrender_api::{ClipId, ClipMode, ColorF, ComplexClipRegion, GradientStop, LineStyle}; +use webrender_api::{LocalClip, RepeatMode, ScrollPolicy, ScrollSensitivity, StickyFrameInfo}; use webrender_api::StickySideConstraint; use webrender_helpers::{ToBorderRadius, ToMixBlendMode, ToRectF, ToTransformStyle}; @@ -146,8 +146,9 @@ pub struct InlineNodeBorderInfo { #[derive(Debug)] struct StackingContextInfo { children: Vec<StackingContext>, - clip_scroll_nodes: Vec<ClipScrollNode>, + clip_scroll_nodes: Vec<ClipScrollNodeIndex>, } + impl StackingContextInfo { fn new() -> StackingContextInfo { StackingContextInfo { @@ -171,8 +172,7 @@ pub struct StackingContextCollectionState { /// StackingContext and ClipScrollNode children for each StackingContext. stacking_context_info: FnvHashMap<StackingContextId, StackingContextInfo>, - /// A map establishing the parent child relationship of every ClipScrollNode. - pub clip_scroll_node_parents: FnvHashMap<ClipId, ClipId>, + pub clip_scroll_nodes: Vec<ClipScrollNode>, /// The current stacking context id, used to keep track of state when building. /// 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 /// 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. /// This is necessary because absolutely positioned items should be clipped /// 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 /// rendered region. @@ -207,17 +207,28 @@ pub struct StackingContextCollectionState { impl 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 { pipeline_id: pipeline_id, - root_stacking_context: StackingContext::root(pipeline_id), + root_stacking_context: StackingContext::root(), stacking_context_info: FnvHashMap::default(), - clip_scroll_node_parents: FnvHashMap::default(), + clip_scroll_nodes: vec![root_node], current_stacking_context_id: StackingContextId::root(), current_real_stacking_context_id: StackingContextId::root(), next_stacking_context_id: StackingContextId::root().next(), - current_clip_and_scroll_info: root_clip_info, - containing_block_clip_and_scroll_info: root_clip_info, + current_clipping_and_scrolling: root_clip_indices, + containing_block_clipping_and_scrolling: root_clip_indices, clip_stack: Vec::new(), containing_block_clip_stack: Vec::new(), parent_stacking_relative_content_box: Rect::zero(), @@ -238,20 +249,18 @@ impl StackingContextCollectionState { info.children.push(stacking_context); } - fn has_clip_scroll_node(&mut self, id: ClipId) -> bool { - self.clip_scroll_node_parents.contains_key(&id) - } - - fn add_clip_scroll_node(&mut self, clip_scroll_node: ClipScrollNode) { + fn add_clip_scroll_node(&mut self, clip_scroll_node: ClipScrollNode) -> ClipScrollNodeIndex { // 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) // stacking context. This ensures that item reordering will not result in an item using // 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 .entry(self.current_real_stacking_context_id) .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. stacking_context_info: FnvHashMap<StackingContextId, StackingContextInfo>, - /// A map establishing the parent child relationship of every ClipScrollNode. - pub clip_scroll_node_parents: FnvHashMap<ClipId, ClipId>, + /// A vector of ClipScrollNodes which will be given ids during WebRender DL conversion. + pub clip_scroll_nodes: Vec<ClipScrollNode>, /// The items in this display list. 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 /// 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 /// new iframe sizes @@ -292,16 +301,16 @@ impl<'a> DisplayListBuildState<'a> { pub fn new(layout_context: &'a LayoutContext, state: StackingContextCollectionState) -> DisplayListBuildState<'a> { - let root_clip_info = ClipAndScrollInfo::simple(layout_context.id.root_scroll_node()); + let root_clip_indices = ClippingAndScrolling::simple(ClipScrollNodeIndex(0)); DisplayListBuildState { layout_context: layout_context, root_stacking_context: state.root_stacking_context, items: FnvHashMap::default(), 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, 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(), } } @@ -311,13 +320,12 @@ impl<'a> DisplayListBuildState<'a> { items.push(display_item); } - fn parent_clip_scroll_node_id(&self, clip_scroll_node_id: ClipId) -> ClipId { - if clip_scroll_node_id.is_root_scroll_node() { - return clip_scroll_node_id; + fn parent_clip_scroll_node_index(&self, index: ClipScrollNodeIndex) -> ClipScrollNodeIndex { + if index.is_root_scroll_node() { + return index; } - debug_assert!(self.clip_scroll_node_parents.contains_key(&clip_scroll_node_id)); - *self.clip_scroll_node_parents.get(&clip_scroll_node_id).unwrap() + self.clip_scroll_nodes[index.0].parent_index } fn is_background_or_border_of_clip_scroll_node(&self, section: DisplayListSection) -> bool { @@ -333,10 +341,11 @@ impl<'a> DisplayListBuildState<'a> { cursor: Option<Cursor>, section: DisplayListSection) -> BaseDisplayItem { - let clip_and_scroll_info = 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)) + let clipping_and_scrolling = if self.is_background_or_border_of_clip_scroll_node(section) { + ClippingAndScrolling::simple( + self.parent_clip_scroll_node_index(self.current_clipping_and_scrolling.scrolling)) } else { - self.current_clip_and_scroll_info + self.current_clipping_and_scrolling }; BaseDisplayItem::new(&bounds, @@ -347,18 +356,18 @@ impl<'a> DisplayListBuildState<'a> { clip, section, self.current_stacking_context_id, - clip_and_scroll_info) + clipping_and_scrolling) } pub fn to_display_list(mut self) -> DisplayList { let mut list = Vec::new(); - let root_context = mem::replace(&mut self.root_stacking_context, - StackingContext::root(self.layout_context.id)); + let root_context = mem::replace(&mut self.root_stacking_context, StackingContext::root()); self.to_display_list_for_stacking_context(&mut list, root_context); DisplayList { list: list, + clip_scroll_nodes: self.clip_scroll_nodes, } } @@ -374,14 +383,13 @@ impl<'a> DisplayListBuildState<'a> { info.children.sort(); - let pipeline_id = self.layout_context.id; 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); } 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.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); list.push(pop_item); } @@ -612,13 +620,14 @@ pub trait FragmentDisplayListBuilding { clip: &Rect<Au>); /// Creates a stacking context for associated fragment. - fn create_stacking_context(&self, - id: StackingContextId, - base_flow: &BaseFlow, - scroll_policy: ScrollPolicy, - context_type: StackingContextType, - parent_clip_and_scroll_info: ClipAndScrollInfo) - -> StackingContext; + fn create_stacking_context( + &self, + id: StackingContextId, + base_flow: &BaseFlow, + scroll_policy: ScrollPolicy, + context_type: StackingContextType, + parent_clipping_and_scrolling: ClippingAndScrolling + ) -> StackingContext; fn unique_id(&self, id_type: IdType) -> u64; @@ -2175,13 +2184,14 @@ impl FragmentDisplayListBuilding for Fragment { } } - fn create_stacking_context(&self, - id: StackingContextId, - base_flow: &BaseFlow, - scroll_policy: ScrollPolicy, - context_type: StackingContextType, - parent_clip_and_scroll_info: ClipAndScrollInfo) - -> StackingContext { + fn create_stacking_context( + &self, + id: StackingContextId, + base_flow: &BaseFlow, + scroll_policy: ScrollPolicy, + context_type: StackingContextType, + parent_clipping_and_scrolling: ClippingAndScrolling + ) -> StackingContext { let border_box = self.stacking_relative_border_box(&base_flow.stacking_relative_position, &base_flow.early_absolute_position_info @@ -2203,18 +2213,20 @@ impl FragmentDisplayListBuilding for Fragment { filters.push(Filter::Opacity(effects.opacity.into())) } - StackingContext::new(id, - context_type, - &border_box, - &overflow, - self.effective_z_index(), - filters.into(), - self.style().get_effects().mix_blend_mode.to_mix_blend_mode(), - self.transform_matrix(&border_box), - self.style().get_used_transform_style().to_transform_style(), - self.perspective_matrix(&border_box), - scroll_policy, - parent_clip_and_scroll_info) + StackingContext::new( + id, + context_type, + &border_box, + &overflow, + self.effective_z_index(), + filters.into(), + self.style().get_effects().mix_blend_mode.to_mix_blend_mode(), + self.transform_matrix(&border_box), + self.style().get_used_transform_style().to_transform_style(), + self.perspective_matrix(&border_box), + scroll_policy, + parent_clipping_and_scrolling + ) } fn build_display_list_for_text_fragment(&self, @@ -2417,7 +2429,7 @@ pub trait BlockFlowDisplayListBuilding { preserved_state: &mut SavedStackingContextCollectionState, stacking_context_type: BlockStackingContextType, flags: StackingContextCollectionFlags) - -> ClipAndScrollInfo; + -> ClippingAndScrolling; fn setup_clip_scroll_node_for_position(&mut self, state: &mut StackingContextCollectionState, border_box: &Rect<Au>); @@ -2428,14 +2440,18 @@ pub trait BlockFlowDisplayListBuilding { state: &mut StackingContextCollectionState, preserved_state: &mut SavedStackingContextCollectionState, stacking_relative_border_box: &Rect<Au>); - fn create_pseudo_stacking_context_for_block(&mut self, - parent_stacking_context_id: StackingContextId, - parent_clip_and_scroll_info: ClipAndScrollInfo, - state: &mut StackingContextCollectionState); - fn create_real_stacking_context_for_block(&mut self, - parent_stacking_context_id: StackingContextId, - parent_clip_and_scroll_info: ClipAndScrollInfo, - state: &mut StackingContextCollectionState); + fn create_pseudo_stacking_context_for_block( + &mut self, + parent_stacking_context_id: StackingContextId, + parent_clip_and_scroll_info: ClippingAndScrolling, + state: &mut StackingContextCollectionState + ); + fn create_real_stacking_context_for_block( + &mut self, + parent_stacking_context_id: StackingContextId, + parent_clipping_and_scrolling: ClippingAndScrolling, + state: &mut StackingContextCollectionState + ); fn build_display_list_for_block(&mut self, state: &mut DisplayListBuildState, border_painting_mode: BorderPaintingMode); @@ -2454,8 +2470,8 @@ pub trait BlockFlowDisplayListBuilding { pub struct SavedStackingContextCollectionState { stacking_context_id: StackingContextId, real_stacking_context_id: StackingContextId, - clip_and_scroll_info: ClipAndScrollInfo, - containing_block_clip_and_scroll_info: ClipAndScrollInfo, + clipping_and_scrolling: ClippingAndScrolling, + containing_block_clipping_and_scrolling: ClippingAndScrolling, clips_pushed: usize, containing_block_clips_pushed: usize, stacking_relative_content_box: Rect<Au>, @@ -2466,8 +2482,8 @@ impl SavedStackingContextCollectionState { SavedStackingContextCollectionState { stacking_context_id: state.current_stacking_context_id, real_stacking_context_id: state.current_real_stacking_context_id, - clip_and_scroll_info: state.current_clip_and_scroll_info, - containing_block_clip_and_scroll_info: state.containing_block_clip_and_scroll_info, + clipping_and_scrolling: state.current_clipping_and_scrolling, + containing_block_clipping_and_scrolling: state.containing_block_clipping_and_scrolling, clips_pushed: 0, containing_block_clips_pushed: 0, stacking_relative_content_box: state.parent_stacking_relative_content_box, @@ -2483,8 +2499,8 @@ impl SavedStackingContextCollectionState { fn restore(self, state: &mut StackingContextCollectionState) { state.current_stacking_context_id = self.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.containing_block_clip_and_scroll_info = self.containing_block_clip_and_scroll_info; + state.current_clipping_and_scrolling = self.clipping_and_scrolling; + state.containing_block_clipping_and_scrolling = self.containing_block_clipping_and_scrolling; state.parent_stacking_relative_content_box = self.stacking_relative_content_box; 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 - // any scroll root that we create. If we create a scroll root, its id will be - // stored in state.current_clip_and_scroll_info. If we create a stacking context, + // any scroll root that we create. If we create a scroll root, its index will be + // 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. - let containing_clip_and_scroll_info = + let containing_clipping_and_scrolling = self.setup_clipping_for_block(state, &mut preserved_state, block_stacking_context_type, flags); 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 { @@ -2612,14 +2628,18 @@ impl BlockFlowDisplayListBuilding for BlockFlow { self.base.collect_stacking_contexts_for_children(state); } BlockStackingContextType::PseudoStackingContext => { - self.create_pseudo_stacking_context_for_block(preserved_state.stacking_context_id, - containing_clip_and_scroll_info, - state); + self.create_pseudo_stacking_context_for_block( + preserved_state.stacking_context_id, + containing_clipping_and_scrolling, + state + ); } BlockStackingContextType::StackingContext => { - self.create_real_stacking_context_for_block(preserved_state.stacking_context_id, - containing_clip_and_scroll_info, - state); + self.create_real_stacking_context_for_block( + preserved_state.stacking_context_id, + containing_clipping_and_scrolling, + state + ); } } @@ -2631,22 +2651,22 @@ impl BlockFlowDisplayListBuilding for BlockFlow { preserved_state: &mut SavedStackingContextCollectionState, stacking_context_type: BlockStackingContextType, flags: StackingContextCollectionFlags) - -> ClipAndScrollInfo { + -> ClippingAndScrolling { // 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. - let containing_clip_and_scroll_info = match self.positioning() { + let containing_clipping_and_scrolling = match self.positioning() { position::T::absolute => { preserved_state.switch_to_containing_block_clip(state); - state.current_clip_and_scroll_info = state.containing_block_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_clipping_and_scrolling } 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() { self.stacking_relative_border_box(CoordinateSystem::Own) @@ -2680,11 +2700,11 @@ impl BlockFlowDisplayListBuilding for BlockFlow { match self.positioning() { 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, @@ -2735,25 +2755,19 @@ impl BlockFlowDisplayListBuilding for BlockFlow { to_sticky_info(sticky_position.left, 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), - 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( + let new_clip_scroll_index = state.add_clip_scroll_node( ClipScrollNode { - id: new_clip_scroll_node_id, - parent_id: parent_id, + id: None, + parent_index: self.clipping_and_scrolling().scrolling, clip: ClippingRegion::from_rect(border_box), content_rect: Rect::zero(), node_type: ClipScrollNodeType::StickyFrame(sticky_frame_info), }, ); - let new_clip_and_scroll_info = ClipAndScrollInfo::simple(new_clip_scroll_node_id); - self.base.clip_and_scroll_info = Some(new_clip_and_scroll_info); - state.current_clip_and_scroll_info = new_clip_and_scroll_info; + let new_clipping_and_scrolling = ClippingAndScrolling::simple(new_clip_scroll_index); + self.base.clipping_and_scrolling = Some(new_clipping_and_scrolling); + state.current_clipping_and_scrolling = new_clipping_and_scrolling; } 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. let new_clip_scroll_node_id = ClipId::new(self.fragment.unique_id(IdType::OverflowClip), 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 && 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 = Size2D::new(content_size.x, content_size.y); - let parent_id = self.clip_and_scroll_info(state.pipeline_id).scroll_node_id; - state.add_clip_scroll_node( + let new_clip_scroll_index = state.add_clip_scroll_node( ClipScrollNode { - id: new_clip_scroll_node_id, - parent_id: parent_id, + id: Some(new_clip_scroll_node_id), + parent_index: self.clipping_and_scrolling().scrolling, clip: clip, content_rect: Rect::new(content_box.origin, content_size), node_type: ClipScrollNodeType::ScrollFrame(sensitivity), }, ); - let new_clip_and_scroll_info = ClipAndScrollInfo::simple(new_clip_scroll_node_id); - self.base.clip_and_scroll_info = Some(new_clip_and_scroll_info); - state.current_clip_and_scroll_info = new_clip_and_scroll_info; + let new_clipping_and_scrolling = ClippingAndScrolling::simple(new_clip_scroll_index); + self.base.clipping_and_scrolling = Some(new_clipping_and_scrolling); + state.current_clipping_and_scrolling = new_clipping_and_scrolling; } /// 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); 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); preserved_state.push_clip(state, &clip_rect, self.positioning()); - let parent_id = self.clip_and_scroll_info(state.pipeline_id).scroll_node_id; - state.add_clip_scroll_node( + let new_index = state.add_clip_scroll_node( ClipScrollNode { - id: new_clip_scroll_node_id, - parent_id: parent_id, + id: None, + parent_index: self.clipping_and_scrolling().scrolling, clip: ClippingRegion::from_rect(&clip_rect), content_rect: Rect::zero(), // content_rect isn't important for clips. node_type: ClipScrollNodeType::Clip, }, ); - let new_clip_and_scroll_info = ClipAndScrollInfo::new(new_clip_scroll_node_id, - new_clip_scroll_node_id); - self.base.clip_and_scroll_info = Some(new_clip_and_scroll_info); - state.current_clip_and_scroll_info = new_clip_and_scroll_info; + let new_indices = ClippingAndScrolling::new(new_index, new_index); + self.base.clipping_and_scrolling = Some(new_indices); + state.current_clipping_and_scrolling = new_indices; } - fn create_pseudo_stacking_context_for_block(&mut self, - parent_stacking_context_id: StackingContextId, - parent_clip_and_scroll_info: ClipAndScrollInfo, - state: &mut StackingContextCollectionState) { + fn create_pseudo_stacking_context_for_block( + &mut self, + parent_stacking_context_id: StackingContextId, + parent_clipping_and_scrolling: ClippingAndScrolling, + state: &mut StackingContextCollectionState + ) { let creation_mode = if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) || self.fragment.style.get_box().position != position::T::static_ { StackingContextType::PseudoPositioned @@ -2897,7 +2893,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow { &self.base, ScrollPolicy::Scrollable, creation_mode, - parent_clip_and_scroll_info); + parent_clipping_and_scrolling); state.add_stacking_context(parent_stacking_context_id, new_context); 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, - parent_stacking_context_id: StackingContextId, - parent_clip_and_scroll_info: ClipAndScrollInfo, - state: &mut StackingContextCollectionState) { + fn create_real_stacking_context_for_block( + &mut self, + parent_stacking_context_id: StackingContextId, + parent_clipping_and_scrolling: ClippingAndScrolling, + state: &mut StackingContextCollectionState + ) { let scroll_policy = if self.is_fixed() { ScrollPolicy::Fixed } else { @@ -2930,7 +2928,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow { &self.base, scroll_policy, StackingContextType::Real, - parent_clip_and_scroll_info); + parent_clipping_and_scrolling + ); state.add_stacking_context(parent_stacking_context_id, stacking_context); self.base.collect_stacking_contexts_for_children(state); @@ -3012,14 +3011,14 @@ pub trait InlineFlowDisplayListBuilding { impl InlineFlowDisplayListBuilding for InlineFlow { fn collect_stacking_contexts_for_inline(&mut self, state: &mut StackingContextCollectionState) { 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); 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(), 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) { @@ -3027,12 +3026,13 @@ impl InlineFlowDisplayListBuilding for InlineFlow { fragment.stacking_context_id = state.generate_stacking_context_id(); let current_stacking_context_id = state.current_stacking_context_id; - let stacking_context = - fragment.create_stacking_context(fragment.stacking_context_id, - &self.base, - ScrollPolicy::Scrollable, - StackingContextType::Real, - state.current_clip_and_scroll_info); + let stacking_context = fragment.create_stacking_context( + fragment.stacking_context_id, + &self.base, + ScrollPolicy::Scrollable, + StackingContextType::Real, + state.current_clipping_and_scrolling + ); state.add_stacking_context(current_stacking_context_id, stacking_context); } 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; } } diff --git a/components/layout/flow.rs b/components/layout/flow.rs index 990e29e0238..31eb4c2ebf6 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -35,11 +35,11 @@ use floats::{Floats, SpeculatedFloatPlacement}; use flow_list::{FlowList, FlowListIterator, MutFlowListIterator}; use flow_ref::{FlowRef, WeakFlowRef}; use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, Overflow}; +use gfx::display_list::ClippingAndScrolling; use gfx_traits::StackingContextId; use gfx_traits::print_tree::PrintTree; use inline::InlineFlow; use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo}; -use msg::constellation_msg::PipelineId; use multicol::MulticolFlow; use parallel::FlowParallelInfo; use serde::ser::{Serialize, SerializeStruct, Serializer}; @@ -63,7 +63,6 @@ use table_colgroup::TableColGroupFlow; use table_row::TableRowFlow; use table_rowgroup::TableRowGroupFlow; use table_wrapper::TableWrapperFlow; -use webrender_api::ClipAndScrollInfo; /// 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. @@ -444,13 +443,10 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static { /// children of this flow. fn print_extra_flow_children(&self, _: &mut PrintTree) { } - fn clip_and_scroll_info(&self, pipeline_id: PipelineId) -> ClipAndScrollInfo { - match base(self).clip_and_scroll_info { + fn clipping_and_scrolling(&self) -> ClippingAndScrolling { + match base(self).clipping_and_scrolling { Some(info) => info, - None => { - debug_assert!(false, "Tried to access scroll root id on Flow before assignment"); - pipeline_id.root_clip_and_scroll_info() - } + None => unreachable!("Tried to access scroll root id on Flow before assignment"), } } } @@ -920,7 +916,9 @@ pub struct BaseFlow { /// list construction. 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 { @@ -1062,7 +1060,7 @@ impl BaseFlow { writing_mode: writing_mode, thread_id: 0, stacking_context_id: StackingContextId::root(), - clip_and_scroll_info: None, + clipping_and_scrolling: None, } } diff --git a/components/layout/table_colgroup.rs b/components/layout/table_colgroup.rs index 4b6af989e25..fdd430aebc6 100644 --- a/components/layout/table_colgroup.rs +++ b/components/layout/table_colgroup.rs @@ -98,7 +98,7 @@ impl Flow for TableColGroupFlow { fn collect_stacking_contexts(&mut self, state: &mut StackingContextCollectionState) { 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>) {} diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 077e43fb45c..2905157db3c 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -313,9 +313,8 @@ impl<'a> BuildDisplayList<'a> { let parent_stacking_context_id = self.state.current_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; - self.state.current_clip_and_scroll_info = - flow.clip_and_scroll_info(self.state.layout_context.id); + let parent_clipping_and_scrolling = self.state.current_clipping_and_scrolling; + self.state.current_clipping_and_scrolling = flow.clipping_and_scrolling(); flow.build_display_list(&mut self.state); 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_clip_and_scroll_info = parent_clip_and_scroll_info; + self.state.current_clipping_and_scrolling = parent_clipping_and_scrolling; } } diff --git a/components/layout/webrender_helpers.rs b/components/layout/webrender_helpers.rs index 1855c63db0a..bed47cfb4d6 100644 --- a/components/layout/webrender_helpers.rs +++ b/components/layout/webrender_helpers.rs @@ -9,14 +9,15 @@ use app_units::Au; use euclid::{Point2D, Vector2D, Rect, SideOffsets2D, Size2D}; -use gfx::display_list::{BorderDetails, BorderRadii, BoxShadowClipMode, ClipScrollNodeType}; -use gfx::display_list::{ClippingRegion, DisplayItem, DisplayList, StackingContextType}; +use gfx::display_list::{BorderDetails, BorderRadii, BoxShadowClipMode, ClipScrollNode}; +use gfx::display_list::{ClipScrollNodeIndex, ClipScrollNodeType, ClippingRegion, DisplayItem}; +use gfx::display_list::{DisplayList, StackingContextType}; use msg::constellation_msg::PipelineId; use style::computed_values::{image_rendering, mix_blend_mode, transform_style}; use style::values::computed::{BorderStyle, Filter}; use style::values::generics::effects::Filter as GenericFilter; -use webrender_api::{self, ClipAndScrollInfo, ComplexClipRegion, DisplayListBuilder}; -use webrender_api::{ClipMode, ExtendMode, LayoutTransform}; +use webrender_api::{self, ClipAndScrollInfo, ClipId, ClipMode, ComplexClipRegion}; +use webrender_api::{DisplayListBuilder, ExtendMode, LayoutTransform}; pub trait WebRenderDisplayListConverter { fn convert_to_webrender(&self, pipeline_id: PipelineId) -> DisplayListBuilder; @@ -24,9 +25,13 @@ pub trait WebRenderDisplayListConverter { trait WebRenderDisplayItemConverter { fn prim_info(&self) -> webrender_api::LayoutPrimitiveInfo; - fn convert_to_webrender(&self, - builder: &mut DisplayListBuilder, - current_clip_and_scroll_info: &mut ClipAndScrollInfo); + fn convert_to_webrender( + &self, + builder: &mut DisplayListBuilder, + clip_scroll_nodes: &[ClipScrollNode], + clip_ids: &mut Vec<Option<ClipId>>, + current_clip_and_scroll_info: &mut ClipAndScrollInfo + ); } trait ToBorderStyle { @@ -227,8 +232,17 @@ impl WebRenderDisplayListConverter for DisplayList { 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); + 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 { - 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 } @@ -249,10 +263,27 @@ impl WebRenderDisplayItemConverter for DisplayItem { } } - fn convert_to_webrender(&self, - builder: &mut DisplayListBuilder, - current_clip_and_scroll_info: &mut ClipAndScrollInfo) { - let clip_and_scroll_info = self.base().clip_and_scroll_info; + fn convert_to_webrender( + &self, + builder: &mut DisplayListBuilder, + 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 { builder.pop_clip_id(); 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::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 item_rect = item.node.clip.main.to_rectf(); - let webrender_id = match item.node.node_type { + let webrender_id = match node.node_type { ClipScrollNodeType::Clip => { - builder.define_clip(Some(our_id), - item_rect, - item.node.clip.get_complex_clips(), - None) + builder.define_clip_with_parent( + node.id, + parent_id, + item_rect, + node.clip.get_complex_clips(), + None + ) } ClipScrollNodeType::ScrollFrame(scroll_sensitivity) => { - builder.define_scroll_frame(Some(our_id), - item.node.content_rect.to_rectf(), - item.node.clip.main.to_rectf(), - item.node.clip.get_complex_clips(), - None, - scroll_sensitivity) + builder.define_scroll_frame_with_parent( + node.id, + parent_id, + node.content_rect.to_rectf(), + node.clip.main.to_rectf(), + node.clip.get_complex_clips(), + None, + scroll_sensitivity + ) } 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); } } } diff --git a/resources/servo.css b/resources/servo.css index 206d3a3f702..d883e0eccb0 100644 --- a/resources/servo.css +++ b/resources/servo.css @@ -189,6 +189,11 @@ svg > * { position: static; margin: 0; 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 { @@ -197,6 +202,7 @@ svg > * { border: none; padding: 0; counter-increment: none; + overflow: visible; } *|*::-servo-anonymous-table-row { @@ -204,6 +210,7 @@ svg > * { position: static; border: none; counter-increment: none; + overflow: visible; } *|*::-servo-anonymous-table-cell { @@ -211,6 +218,7 @@ svg > * { position: static; border: none; counter-increment: none; + overflow: visible; } *|*::-servo-anonymous-block { diff --git a/tests/unit/metrics/paint_time.rs b/tests/unit/metrics/paint_time.rs index 033e618269a..2148c71f3ee 100644 --- a/tests/unit/metrics/paint_time.rs +++ b/tests/unit/metrics/paint_time.rs @@ -61,7 +61,8 @@ fn test_common(display_list: &DisplayList, epoch: Epoch) -> PaintTimeMetrics { #[test] fn test_first_paint_setter() { let empty_display_list = DisplayList { - list: Vec::new() + list: Vec::new(), + clip_scroll_nodes: Vec::new(), }; let epoch = Epoch(0); let mut paint_time_metrics = test_common(&empty_display_list, epoch); @@ -74,7 +75,7 @@ fn test_first_paint_setter() { #[test] fn test_first_contentful_paint_setter() { let image = DisplayItem::Image(Box::new(ImageDisplayItem { - base: BaseDisplayItem::empty(TEST_PIPELINE_ID), + base: BaseDisplayItem::empty(), webrender_image: WebRenderImageInfo { width: 1, height: 1, @@ -87,7 +88,8 @@ fn test_first_contentful_paint_setter() { image_rendering: image_rendering::T::auto, })); let display_list = DisplayList { - list: vec![image] + list: vec![image], + clip_scroll_nodes: Vec::new(), }; let epoch = Epoch(0); let mut paint_time_metrics = test_common(&display_list, epoch); |