aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2018-03-06 14:54:38 +0100
committerMartin Robinson <mrobinson@igalia.com>2018-03-06 21:26:22 +0100
commite100a7212224a4dc3558ec2a0824e5168bbe7a27 (patch)
treee7eb0f3b254699a25ad60a1697a6523dd5eae596 /components/layout
parent226d9a5b0e69185b95c62e79b81044beba477654 (diff)
downloadservo-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.rs8
-rw-r--r--components/layout/display_list/builder.rs247
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(