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.
This commit is contained in:
Martin Robinson 2018-03-06 14:54:38 +01:00
parent 226d9a5b0e
commit e100a72122
2 changed files with 135 additions and 120 deletions

View file

@ -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,
}

View file

@ -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(