diff options
author | Martin Robinson <mrobinson@igalia.com> | 2018-03-06 14:54:38 +0100 |
---|---|---|
committer | Martin Robinson <mrobinson@igalia.com> | 2018-03-06 21:26:22 +0100 |
commit | e100a7212224a4dc3558ec2a0824e5168bbe7a27 (patch) | |
tree | e7eb0f3b254699a25ad60a1697a6523dd5eae596 /components/layout | |
parent | 226d9a5b0e69185b95c62e79b81044beba477654 (diff) | |
download | servo-e100a7212224a4dc3558ec2a0824e5168bbe7a27.tar.gz servo-e100a7212224a4dc3558ec2a0824e5168bbe7a27.zip |
Stop using LocalClip::RoundedRect
We would like to remove this functionality from WebRender, so convert
its use to clip scroll nodes. This change also removes the redundant
BlocBlockStackingContextType in favor of Option<StackingContextType>,
which is just as expressive. This simplifies the code a bit.
Diffstat (limited to 'components/layout')
-rw-r--r-- | components/layout/block.rs | 8 | ||||
-rw-r--r-- | components/layout/display_list/builder.rs | 247 |
2 files changed, 135 insertions, 120 deletions
diff --git a/components/layout/block.rs b/components/layout/block.rs index d7505e7b8ba..225def73677 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -3109,11 +3109,3 @@ impl ISizeAndMarginsComputer for InlineFlexItem { fragment.margin.inline_end) } } - -/// A stacking context, a pseudo-stacking context, or a non-stacking context. -#[derive(Clone, Copy, PartialEq)] -pub enum BlockStackingContextType { - NonstackingContext, - PseudoStackingContext, - StackingContext, -} diff --git a/components/layout/display_list/builder.rs b/components/layout/display_list/builder.rs index ec660607251..32a5ae19d3a 100644 --- a/components/layout/display_list/builder.rs +++ b/components/layout/display_list/builder.rs @@ -11,7 +11,7 @@ #![deny(unsafe_code)] use app_units::{Au, AU_PER_PX}; -use block::{BlockFlow, BlockStackingContextType}; +use block::BlockFlow; use canvas_traits::canvas::{CanvasMsg, FromLayoutMsg}; use context::LayoutContext; use display_list::ToLayout; @@ -73,11 +73,10 @@ use style_traits::CSSPixel; use style_traits::ToCss; use style_traits::cursor::CursorKind; use table_cell::CollapsedBordersForCell; -use webrender_api::{self, BorderRadius, BorderSide, BoxShadowClipMode, ClipMode, ColorF}; -use webrender_api::{ComplexClipRegion, ExternalScrollId, FilterOp, GlyphInstance}; -use webrender_api::{ImageRendering, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D}; -use webrender_api::{LineStyle, LocalClip, NormalBorder, ScrollPolicy}; -use webrender_api::{ScrollSensitivity, StickyOffsetBounds}; +use webrender_api::{self, BorderRadius, BorderSide, BoxShadowClipMode, ColorF, ExternalScrollId}; +use webrender_api::{FilterOp, GlyphInstance, ImageRendering, LayoutRect, LayoutSize}; +use webrender_api::{LayoutTransform, LayoutVector2D, LineStyle, LocalClip, NormalBorder}; +use webrender_api::{ScrollPolicy, ScrollSensitivity, StickyOffsetBounds}; fn establishes_containing_block_for_absolute( flags: StackingContextCollectionFlags, @@ -162,13 +161,15 @@ pub struct InlineNodeBorderInfo { struct StackingContextInfo { children: Vec<StackingContext>, clip_scroll_nodes: Vec<ClipScrollNodeIndex>, + real_stacking_context_id: StackingContextId, } impl StackingContextInfo { - fn new() -> StackingContextInfo { + fn new(real_stacking_context_id: StackingContextId) -> StackingContextInfo { StackingContextInfo { children: Vec::new(), clip_scroll_nodes: Vec::new(), + real_stacking_context_id, } } @@ -236,10 +237,16 @@ impl StackingContextCollectionState { ), }; + let mut stacking_context_info = FnvHashMap::default(); + stacking_context_info.insert( + StackingContextId::root(), + StackingContextInfo::new(StackingContextId::root()) + ); + StackingContextCollectionState { pipeline_id: pipeline_id, root_stacking_context: StackingContext::root(), - stacking_context_info: FnvHashMap::default(), + stacking_context_info, clip_scroll_nodes: vec![root_node], current_stacking_context_id: StackingContextId::root(), current_real_stacking_context_id: StackingContextId::root(), @@ -252,9 +259,25 @@ impl StackingContextCollectionState { } } - fn generate_stacking_context_id(&mut self) -> StackingContextId { + fn allocate_stacking_context_info( + &mut self, + stacking_context_type: StackingContextType + ) -> StackingContextId { let next_stacking_context_id = self.next_stacking_context_id.next(); - mem::replace(&mut self.next_stacking_context_id, next_stacking_context_id) + let allocated_id = + mem::replace(&mut self.next_stacking_context_id, next_stacking_context_id); + + let real_stacking_context_id = match stacking_context_type { + StackingContextType::Real => allocated_id, + _ => self.current_real_stacking_context_id, + }; + + self.stacking_context_info.insert( + allocated_id, + StackingContextInfo::new(real_stacking_context_id) + ); + + allocated_id } fn add_stacking_context( @@ -262,10 +285,7 @@ impl StackingContextCollectionState { parent_id: StackingContextId, stacking_context: StackingContext, ) { - let info = self.stacking_context_info - .entry(parent_id) - .or_insert(StackingContextInfo::new()); - info.children.push(stacking_context); + self.stacking_context_info.get_mut(&parent_id).unwrap().children.push(stacking_context); } fn add_clip_scroll_node(&mut self, clip_scroll_node: ClipScrollNode) -> ClipScrollNodeIndex { @@ -275,10 +295,11 @@ impl StackingContextCollectionState { // the scroll root before it is defined. 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(index); + self.stacking_context_info + .get_mut(&self.current_real_stacking_context_id) + .unwrap() + .clip_scroll_nodes + .push(index); index } } @@ -390,6 +411,34 @@ impl<'a> DisplayListBuildState<'a> { ) } + fn add_late_clip_node(&mut self, rect: LayoutRect, radii: BorderRadius) -> ClipScrollNodeIndex { + let mut clip = ClippingRegion::from_rect(rect); + clip.intersect_with_rounded_rect(rect, radii); + + let node = ClipScrollNode { + parent_index: self.current_clipping_and_scrolling.scrolling, + clip, + content_rect: LayoutRect::zero(), // content_rect isn't important for clips. + node_type: ClipScrollNodeType::Clip, + }; + + // 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_nodes.push(node); + let index = ClipScrollNodeIndex(self.clip_scroll_nodes.len() - 1); + let real_stacking_context_id = + self.stacking_context_info[&self.current_stacking_context_id].real_stacking_context_id; + self.stacking_context_info + .get_mut(&real_stacking_context_id) + .unwrap() + .clip_scroll_nodes + .push(index); + + index + } + 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()); @@ -413,9 +462,7 @@ impl<'a> DisplayListBuildState<'a> { child_items.sort_by(|a, b| a.base().section.cmp(&b.base().section)); child_items.reverse(); - let mut info = self.stacking_context_info - .remove(&stacking_context.id) - .unwrap_or_else(StackingContextInfo::new); + let mut info = self.stacking_context_info.remove(&stacking_context.id).unwrap(); info.children.sort(); @@ -801,18 +848,15 @@ impl FragmentDisplayListBuilding for Fragment { }, } - let clip = if !border_radii.is_zero() { - LocalClip::RoundedRect( - bounds.to_layout(), - ComplexClipRegion::new(bounds.to_layout(), border_radii, ClipMode::Clip), - ) - } else { - LocalClip::Rect(bounds.to_layout()) - }; + let previous_clipping_and_scrolling = state.current_clipping_and_scrolling; + if !border_radii.is_zero() { + let clip_id = state.add_late_clip_node(bounds.to_layout(), border_radii); + state.current_clipping_and_scrolling = ClippingAndScrolling::simple(clip_id); + } let base = state.create_base_display_item( &bounds, - clip, + LocalClip::Rect(bounds.to_layout()), self.node, style.get_cursor(CursorKind::Default), display_list_section, @@ -822,6 +866,8 @@ impl FragmentDisplayListBuilding for Fragment { color: background_color.to_layout(), }))); + state.current_clipping_and_scrolling = previous_clipping_and_scrolling; + // The background image is painted on top of the background color. // Implements background image, per spec: // http://www.w3.org/TR/CSS21/colors.html#background @@ -1608,25 +1654,31 @@ impl FragmentDisplayListBuilding for Fragment { stacking_relative_border_box: &Rect<Au>, clip: &Rect<Au>, ) { + let previous_clipping_and_scrolling = state.current_clipping_and_scrolling; + // Compute the context box position relative to the parent stacking context. let stacking_relative_content_box = self.stacking_relative_content_box(stacking_relative_border_box); - // Adjust the clipping region as necessary to account for `border-radius`. - let build_local_clip = |style: &ComputedValues| { - let radii = build_border_radius_for_inner_rect(&stacking_relative_border_box, style); + let create_base_display_item = |state: &mut DisplayListBuildState| { + let layout_rect = stacking_relative_border_box.to_layout(); + + // Adjust the clipping region as necessary to account for `border-radius`. + let radii = + build_border_radius_for_inner_rect(&stacking_relative_border_box, &self.style); + if !radii.is_zero() { - LocalClip::RoundedRect( - stacking_relative_border_box.to_layout(), - ComplexClipRegion::new( - stacking_relative_content_box.to_layout(), - radii, - ClipMode::Clip, - ), - ) - } else { - LocalClip::Rect(stacking_relative_border_box.to_layout()) + let clip_id = state.add_late_clip_node(layout_rect, radii); + state.current_clipping_and_scrolling = ClippingAndScrolling::simple(clip_id); } + + state.create_base_display_item( + &stacking_relative_content_box, + LocalClip::Rect(layout_rect), + self.node, + self.style.get_cursor(CursorKind::Default), + DisplayListSection::Content, + ) }; match self.specific { @@ -1707,15 +1759,9 @@ impl FragmentDisplayListBuilding for Fragment { None => return warn!("No pipeline id for iframe {}.", browsing_context_id), }; - let base = state.create_base_display_item( - &stacking_relative_content_box, - build_local_clip(&self.style), - self.node, - self.style.get_cursor(CursorKind::Default), - DisplayListSection::Content, - ); + let base = create_base_display_item(state); let item = DisplayItem::Iframe(Box::new(IframeDisplayItem { - base: base, + base, iframe: pipeline_id, })); @@ -1730,15 +1776,9 @@ impl FragmentDisplayListBuilding for Fragment { SpecificFragmentInfo::Image(ref image_fragment) => { // Place the image into the display list. if let Some(ref image) = image_fragment.image { - let base = state.create_base_display_item( - &stacking_relative_content_box, - build_local_clip(&self.style), - self.node, - self.style.get_cursor(CursorKind::Default), - DisplayListSection::Content, - ); + let base = create_base_display_item(state); state.add_display_item(DisplayItem::Image(Box::new(ImageDisplayItem { - base: base, + base, webrender_image: WebRenderImageInfo::from_image(image), stretch_size: stacking_relative_content_box.size.to_layout(), tile_spacing: LayoutSize::zero(), @@ -1765,15 +1805,9 @@ impl FragmentDisplayListBuilding for Fragment { }, }; - let base = state.create_base_display_item( - &stacking_relative_content_box, - build_local_clip(&self.style), - self.node, - self.style.get_cursor(CursorKind::Default), - DisplayListSection::Content, - ); + let base = create_base_display_item(state); let display_item = DisplayItem::Image(Box::new(ImageDisplayItem { - base: base, + base, webrender_image: WebRenderImageInfo { width: computed_width as u32, height: computed_height as u32, @@ -1794,6 +1828,8 @@ impl FragmentDisplayListBuilding for Fragment { panic!("Shouldn't see table column fragments here.") }, } + + state.current_clipping_and_scrolling = previous_clipping_and_scrolling; } fn create_stacking_context( @@ -2061,7 +2097,7 @@ pub trait BlockFlowDisplayListBuilding { &mut self, state: &mut StackingContextCollectionState, preserved_state: &mut SavedStackingContextCollectionState, - stacking_context_type: BlockStackingContextType, + stacking_context_type: Option<StackingContextType>, flags: StackingContextCollectionFlags, ) -> ClippingAndScrolling; fn setup_clip_scroll_node_for_position( @@ -2082,6 +2118,7 @@ pub trait BlockFlowDisplayListBuilding { ); fn create_pseudo_stacking_context_for_block( &mut self, + stacking_context_type: StackingContextType, parent_stacking_context_id: StackingContextId, parent_clip_and_scroll_info: ClippingAndScrolling, state: &mut StackingContextCollectionState, @@ -2108,10 +2145,10 @@ pub trait BlockFlowDisplayListBuilding { background: &style_structs::Background, background_color: RGBA); - fn block_stacking_context_type( + fn stacking_context_type( &self, flags: StackingContextCollectionFlags, - ) -> BlockStackingContextType; + ) -> Option<StackingContextType>; } /// This structure manages ensuring that modification to StackingContextCollectionState is @@ -2267,15 +2304,14 @@ impl BlockFlowDisplayListBuilding for BlockFlow { ) { let mut preserved_state = SavedStackingContextCollectionState::new(state); - let block_stacking_context_type = self.block_stacking_context_type(flags); - self.base.stacking_context_id = match block_stacking_context_type { - BlockStackingContextType::NonstackingContext => state.current_stacking_context_id, - BlockStackingContextType::PseudoStackingContext | - BlockStackingContextType::StackingContext => state.generate_stacking_context_id(), + let stacking_context_type = self.stacking_context_type(flags); + self.base.stacking_context_id = match stacking_context_type { + None => state.current_stacking_context_id, + Some(sc_type) => state.allocate_stacking_context_info(sc_type), }; state.current_stacking_context_id = self.base.stacking_context_id; - if block_stacking_context_type == BlockStackingContextType::StackingContext { + if stacking_context_type == Some(StackingContextType::Real) { state.current_real_stacking_context_id = self.base.stacking_context_id; } @@ -2286,7 +2322,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow { let containing_clipping_and_scrolling = self.setup_clipping_for_block( state, &mut preserved_state, - block_stacking_context_type, + stacking_context_type, flags, ); @@ -2294,19 +2330,18 @@ impl BlockFlowDisplayListBuilding for BlockFlow { state.containing_block_clipping_and_scrolling = state.current_clipping_and_scrolling; } - match block_stacking_context_type { - BlockStackingContextType::NonstackingContext => { - self.base.collect_stacking_contexts_for_children(state); - }, - BlockStackingContextType::PseudoStackingContext => { - self.create_pseudo_stacking_context_for_block( + match stacking_context_type { + None => self.base.collect_stacking_contexts_for_children(state), + Some(StackingContextType::Real) => { + self.create_real_stacking_context_for_block( preserved_state.stacking_context_id, containing_clipping_and_scrolling, state, ); }, - BlockStackingContextType::StackingContext => { - self.create_real_stacking_context_for_block( + Some(stacking_context_type) => { + self.create_pseudo_stacking_context_for_block( + stacking_context_type, preserved_state.stacking_context_id, containing_clipping_and_scrolling, state, @@ -2321,7 +2356,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow { &mut self, state: &mut StackingContextCollectionState, preserved_state: &mut SavedStackingContextCollectionState, - stacking_context_type: BlockStackingContextType, + stacking_context_type: Option<StackingContextType>, flags: StackingContextCollectionFlags, ) -> ClippingAndScrolling { // If this block is absolutely positioned, we should be clipped and positioned by @@ -2347,7 +2382,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow { self.stacking_relative_border_box(CoordinateSystem::Parent) }; - if stacking_context_type == BlockStackingContextType::StackingContext { + if stacking_context_type == Some(StackingContextType::Real) { self.transform_clip_to_coordinate_space(state, preserved_state); } @@ -2578,26 +2613,16 @@ impl BlockFlowDisplayListBuilding for BlockFlow { fn create_pseudo_stacking_context_for_block( &mut self, + stacking_context_type: StackingContextType, parent_stacking_context_id: StackingContextId, parent_clipping_and_scrolling: ClippingAndScrolling, state: &mut StackingContextCollectionState, ) { - let creation_mode = if self.base - .flags - .contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) || - self.fragment.style.get_box().position != StylePosition::Static - { - StackingContextType::PseudoPositioned - } else { - assert!(self.base.flags.is_float()); - StackingContextType::PseudoFloat - }; - let new_context = self.fragment.create_stacking_context( self.base.stacking_context_id, &self.base, ScrollPolicy::Scrollable, - creation_mode, + stacking_context_type, parent_clipping_and_scrolling, ); state.add_stacking_context(parent_stacking_context_id, new_context); @@ -2694,34 +2719,31 @@ impl BlockFlowDisplayListBuilding for BlockFlow { } #[inline] - fn block_stacking_context_type( + fn stacking_context_type( &self, flags: StackingContextCollectionFlags, - ) -> BlockStackingContextType { + ) -> Option<StackingContextType>{ if flags.contains(StackingContextCollectionFlags::NEVER_CREATES_STACKING_CONTEXT) { - return BlockStackingContextType::NonstackingContext; + return None; } if self.fragment.establishes_stacking_context() { - return BlockStackingContextType::StackingContext; + return Some(StackingContextType::Real); } - if self.base - .flags - .contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) - { - return BlockStackingContextType::PseudoStackingContext; + if self.base.flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) { + return Some(StackingContextType::PseudoPositioned); } if self.fragment.style.get_box().position != StylePosition::Static { - return BlockStackingContextType::PseudoStackingContext; + return Some(StackingContextType::PseudoPositioned); } if self.base.flags.is_float() { - return BlockStackingContextType::PseudoStackingContext; + return Some(StackingContextType::PseudoFloat); } - BlockStackingContextType::NonstackingContext + None } } @@ -2757,7 +2779,8 @@ impl InlineFlowDisplayListBuilding for InlineFlow { if !fragment.collect_stacking_contexts_for_blocklike_fragment(state) { if fragment.establishes_stacking_context() { - fragment.stacking_context_id = state.generate_stacking_context_id(); + fragment.stacking_context_id = + state.allocate_stacking_context_info(StackingContextType::Real); let current_stacking_context_id = state.current_stacking_context_id; let stacking_context = fragment.create_stacking_context( |