diff options
Diffstat (limited to 'components/layout/display_list_builder.rs')
-rw-r--r-- | components/layout/display_list_builder.rs | 130 |
1 files changed, 71 insertions, 59 deletions
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index f8b26899b57..5e238a683fe 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -71,8 +71,8 @@ use style_traits::CSSPixel; use style_traits::ToCss; use style_traits::cursor::Cursor; use table_cell::CollapsedBordersForCell; -use webrender_api::{ClipId, ColorF, ComplexClipRegion, GradientStop, LocalClip, RepeatMode}; -use webrender_api::{LineStyle, ScrollPolicy, ScrollSensitivity, TransformStyle}; +use webrender_api::{ClipAndScrollInfo, ClipId, ColorF, ComplexClipRegion, GradientStop, LineStyle}; +use webrender_api::{LocalClip, RepeatMode, ScrollPolicy, ScrollSensitivity, TransformStyle}; use webrender_helpers::{ToBorderRadius, ToMixBlendMode, ToRectF, ToTransformStyle}; trait ResolvePercentage { @@ -169,14 +169,14 @@ pub struct DisplayListBuildState<'a> { /// recursively building and processing the display list. pub current_stacking_context_id: StackingContextId, - /// The current scroll root id, used to keep track of state when + /// The current clip and scroll info, used to keep track of state when /// recursively building and processing the display list. - pub current_scroll_root_id: ClipId, + pub current_clip_and_scroll_info: ClipAndScrollInfo, - /// The scroll root id of the first ancestor which defines a containing block. + /// The clip and scroll info of the first ancestor which defines a containing block. /// This is necessary because absolutely positioned items should be clipped /// by their containing block's scroll root. - pub containing_block_scroll_root_id: ClipId, + pub containing_block_clip_and_scroll_info: ClipAndScrollInfo, /// Vector containing iframe sizes, used to inform the constellation about /// new iframe sizes @@ -196,6 +196,7 @@ pub struct DisplayListBuildState<'a> { impl<'a> DisplayListBuildState<'a> { pub fn new(layout_context: &'a LayoutContext) -> DisplayListBuildState<'a> { + let root_clip_info = ClipAndScrollInfo::simple(layout_context.id.root_scroll_node()); DisplayListBuildState { layout_context: layout_context, root_stacking_context: StackingContext::root(layout_context.id), @@ -204,8 +205,8 @@ impl<'a> DisplayListBuildState<'a> { scroll_root_parents: HashMap::new(), processing_scroll_root_element: false, current_stacking_context_id: StackingContextId::root(), - current_scroll_root_id: layout_context.id.root_scroll_node(), - containing_block_scroll_root_id: layout_context.id.root_scroll_node(), + current_clip_and_scroll_info: root_clip_info, + containing_block_clip_and_scroll_info: root_clip_info, iframe_sizes: Vec::new(), clip_stack: Vec::new(), containing_block_clip_stack: Vec::new(), @@ -249,6 +250,12 @@ impl<'a> DisplayListBuildState<'a> { *self.scroll_root_parents.get(&scroll_root_id).unwrap() } + fn is_background_or_border_of_scroll_root(&self, section: DisplayListSection) -> bool { + (section == DisplayListSection::BackgroundAndBorders || + section == DisplayListSection::BlockBackgroundsAndBorders) && + self.processing_scroll_root_element + } + fn create_base_display_item(&self, bounds: &Rect<Au>, clip: LocalClip, @@ -256,12 +263,10 @@ impl<'a> DisplayListBuildState<'a> { cursor: Option<Cursor>, section: DisplayListSection) -> BaseDisplayItem { - let scroll_root_id = if (section == DisplayListSection::BackgroundAndBorders || - section == DisplayListSection::BlockBackgroundsAndBorders) && - self.processing_scroll_root_element { - self.parent_scroll_root_id(self.current_scroll_root_id) + let clip_and_scroll_info = if self.is_background_or_border_of_scroll_root(section) { + ClipAndScrollInfo::simple(self.parent_scroll_root_id(self.current_clip_and_scroll_info.scroll_node_id)) } else { - self.current_scroll_root_id + self.current_clip_and_scroll_info }; BaseDisplayItem::new(&bounds, @@ -272,7 +277,7 @@ impl<'a> DisplayListBuildState<'a> { clip, section, self.current_stacking_context_id, - scroll_root_id) + clip_and_scroll_info) } pub fn to_display_list(mut self) -> DisplayList { @@ -548,7 +553,7 @@ pub trait FragmentDisplayListBuilding { base_flow: &BaseFlow, scroll_policy: ScrollPolicy, mode: StackingContextCreationMode, - parent_scroll_id: ClipId) + parent_clip_and_scroll_info: ClipAndScrollInfo) -> StackingContext; @@ -2029,7 +2034,7 @@ impl FragmentDisplayListBuilding for Fragment { base_flow: &BaseFlow, scroll_policy: ScrollPolicy, mode: StackingContextCreationMode, - parent_scroll_id: ClipId) + parent_clip_and_scroll_info: ClipAndScrollInfo) -> StackingContext { let border_box = self.stacking_relative_border_box(&base_flow.stacking_relative_position, @@ -2069,7 +2074,7 @@ impl FragmentDisplayListBuilding for Fragment { self.style().get_used_transform_style().to_transform_style(), self.perspective_matrix(&border_box), scroll_policy, - parent_scroll_id) + parent_clip_and_scroll_info) } fn build_display_list_for_text_fragment(&self, @@ -2255,7 +2260,7 @@ pub trait BlockFlowDisplayListBuilding { state: &mut DisplayListBuildState, preserved_state: &mut PreservedDisplayListState, stacking_context_type: BlockStackingContextType) - -> ClipId; + -> ClipAndScrollInfo; fn setup_scroll_root_for_overflow(&mut self, state: &mut DisplayListBuildState, border_box: &Rect<Au>); @@ -2265,11 +2270,11 @@ pub trait BlockFlowDisplayListBuilding { stacking_relative_border_box: &Rect<Au>); fn create_pseudo_stacking_context_for_block(&mut self, parent_stacking_context_id: StackingContextId, - parent_scroll_root_id: ClipId, + parent_clip_and_scroll_info: ClipAndScrollInfo, state: &mut DisplayListBuildState); fn create_real_stacking_context_for_block(&mut self, parent_stacking_context_id: StackingContextId, - parent_scroll_root_id: ClipId, + parent_clip_and_scroll_info: ClipAndScrollInfo, state: &mut DisplayListBuildState); fn build_display_list_for_block(&mut self, state: &mut DisplayListBuildState, @@ -2283,8 +2288,8 @@ pub trait BlockFlowDisplayListBuilding { /// TODO(mrobinson): It would be nice to use RAII here to avoid having to call restore. pub struct PreservedDisplayListState { stacking_context_id: StackingContextId, - scroll_root_id: ClipId, - containing_block_scroll_root_id: ClipId, + clip_and_scroll_info: ClipAndScrollInfo, + containing_block_clip_and_scroll_info: ClipAndScrollInfo, clips_pushed: usize, containing_block_clips_pushed: usize, transform_style: TransformStyle, @@ -2294,8 +2299,8 @@ impl PreservedDisplayListState { fn new(state: &mut DisplayListBuildState) -> PreservedDisplayListState { PreservedDisplayListState { stacking_context_id: state.current_stacking_context_id, - scroll_root_id: state.current_scroll_root_id, - containing_block_scroll_root_id: state.containing_block_scroll_root_id, + clip_and_scroll_info: state.current_clip_and_scroll_info, + containing_block_clip_and_scroll_info: state.containing_block_clip_and_scroll_info, clips_pushed: 0, containing_block_clips_pushed: 0, transform_style: state.current_transform_style, @@ -2310,8 +2315,8 @@ impl PreservedDisplayListState { fn restore(self, state: &mut DisplayListBuildState) { state.current_stacking_context_id = self.stacking_context_id; - state.current_scroll_root_id = self.scroll_root_id; - state.containing_block_scroll_root_id = self.containing_block_scroll_root_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; let truncate_length = state.clip_stack.len() - self.clips_pushed; state.clip_stack.truncate(truncate_length); @@ -2417,14 +2422,12 @@ 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_scroll_root_id. If we should create a stacking context, - // we don't want it to be clipped by its own scroll root. - let containing_scroll_root_id = self.setup_clipping_for_block(state, - &mut preserved_state, - block_stacking_context_type); - + // stored in state.current_clip_and_scroll_info. 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 = + self.setup_clipping_for_block(state, &mut preserved_state, block_stacking_context_type); if establishes_containing_block_for_absolute(self.positioning()) { - state.containing_block_scroll_root_id = state.current_scroll_root_id; + state.containing_block_clip_and_scroll_info = state.current_clip_and_scroll_info; } match block_stacking_context_type { @@ -2433,12 +2436,12 @@ impl BlockFlowDisplayListBuilding for BlockFlow { } BlockStackingContextType::PseudoStackingContext => { self.create_pseudo_stacking_context_for_block(preserved_state.stacking_context_id, - containing_scroll_root_id, + containing_clip_and_scroll_info, state); } BlockStackingContextType::StackingContext => { self.create_real_stacking_context_for_block(preserved_state.stacking_context_id, - containing_scroll_root_id, + containing_clip_and_scroll_info, state); } } @@ -2450,22 +2453,22 @@ impl BlockFlowDisplayListBuilding for BlockFlow { state: &mut DisplayListBuildState, preserved_state: &mut PreservedDisplayListState, stacking_context_type: BlockStackingContextType) - -> ClipId { + -> ClipAndScrollInfo { // 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_scroll_root_id = match self.positioning() { + let containing_clip_and_scroll_info = match self.positioning() { position::T::absolute => { preserved_state.switch_to_containing_block_clip(state); - state.current_scroll_root_id = state.containing_block_scroll_root_id; - state.containing_block_scroll_root_id + state.current_clip_and_scroll_info = state.containing_block_clip_and_scroll_info; + state.containing_block_clip_and_scroll_info } position::T::fixed => { preserved_state.push_clip(state, &max_rect(), position::T::fixed); - state.current_scroll_root_id + state.current_clip_and_scroll_info } - _ => state.current_scroll_root_id, + _ => state.current_clip_and_scroll_info, }; - self.base.scroll_root_id = Some(containing_scroll_root_id); + self.base.clip_and_scroll_info = Some(containing_clip_and_scroll_info); let coordinate_system = if self.fragment.establishes_stacking_context() { CoordinateSystem::Own @@ -2489,11 +2492,11 @@ impl BlockFlowDisplayListBuilding for BlockFlow { match self.positioning() { position::T::absolute | position::T::relative | position::T::fixed => - state.containing_block_scroll_root_id = state.current_scroll_root_id, + state.containing_block_clip_and_scroll_info = state.current_clip_and_scroll_info, _ => {} } - containing_scroll_root_id + containing_clip_and_scroll_info } fn setup_scroll_root_for_overflow(&mut self, @@ -2542,7 +2545,7 @@ 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.scroll_root_id(state.layout_context.id); + let parent_id = self.clip_and_scroll_info(state.layout_context.id).scroll_node_id; state.add_scroll_root( ScrollRoot { id: new_scroll_root_id, @@ -2554,8 +2557,9 @@ impl BlockFlowDisplayListBuilding for BlockFlow { self.base.stacking_context_id ); - self.base.scroll_root_id = Some(new_scroll_root_id); - state.current_scroll_root_id = new_scroll_root_id; + let new_clip_and_scroll_info = ClipAndScrollInfo::simple(new_scroll_root_id); + self.base.clip_and_scroll_info = Some(new_clip_and_scroll_info); + state.current_clip_and_scroll_info = new_clip_and_scroll_info; } /// Adds a scroll root for a block to take the `clip` property into account @@ -2570,6 +2574,13 @@ impl BlockFlowDisplayListBuilding for BlockFlow { _ => return, }; + // CSS `clip` should only apply to position:absolute or positione:fixed elements. + // CSS Masking Appendix A: "Applies to: Absolutely positioned elements." + match self.positioning() { + position::T::absolute | position::T::fixed => {} + _ => return, + } + let clip_origin = Point2D::new(stacking_relative_border_box.origin.x + style_clip_rect.left.unwrap_or(Au(0)), stacking_relative_border_box.origin.y + @@ -2595,7 +2606,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow { let clip_rect = Rect::new(clip_origin, clip_size); preserved_state.push_clip(state, &clip_rect, self.positioning()); - let parent_id = self.scroll_root_id(state.layout_context.id); + let parent_id = self.clip_and_scroll_info(state.layout_context.id).scroll_node_id; state.add_scroll_root( ScrollRoot { id: new_scroll_root_id, @@ -2607,13 +2618,14 @@ impl BlockFlowDisplayListBuilding for BlockFlow { self.base.stacking_context_id ); - self.base.scroll_root_id = Some(new_scroll_root_id); - state.current_scroll_root_id = new_scroll_root_id; + let new_clip_and_scroll_info = ClipAndScrollInfo::new(new_scroll_root_id, new_scroll_root_id); + self.base.clip_and_scroll_info = Some(new_clip_and_scroll_info); + state.current_clip_and_scroll_info = new_clip_and_scroll_info; } fn create_pseudo_stacking_context_for_block(&mut self, parent_stacking_context_id: StackingContextId, - parent_scroll_root_id: ClipId, + parent_clip_and_scroll_info: ClipAndScrollInfo, state: &mut DisplayListBuildState) { let creation_mode = if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) || self.fragment.style.get_box().position != position::T::static_ { @@ -2627,7 +2639,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow { &self.base, ScrollPolicy::Scrollable, creation_mode, - parent_scroll_root_id); + parent_clip_and_scroll_info); state.add_stacking_context(parent_stacking_context_id, new_context); self.base.collect_stacking_contexts_for_children(state); @@ -2647,7 +2659,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow { fn create_real_stacking_context_for_block(&mut self, parent_stacking_context_id: StackingContextId, - parent_scroll_root_id: ClipId, + parent_clip_and_scroll_info: ClipAndScrollInfo, state: &mut DisplayListBuildState) { let scroll_policy = if self.is_fixed() { ScrollPolicy::Fixed @@ -2660,7 +2672,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow { &self.base, scroll_policy, StackingContextCreationMode::Normal, - parent_scroll_root_id); + parent_clip_and_scroll_info); state.add_stacking_context(parent_stacking_context_id, stacking_context); self.base.collect_stacking_contexts_for_children(state); @@ -2715,13 +2727,13 @@ pub trait InlineFlowDisplayListBuilding { impl InlineFlowDisplayListBuilding for InlineFlow { fn collect_stacking_contexts_for_inline(&mut self, state: &mut DisplayListBuildState) { self.base.stacking_context_id = state.current_stacking_context_id; - self.base.scroll_root_id = Some(state.current_scroll_root_id); + self.base.clip_and_scroll_info = Some(state.current_clip_and_scroll_info); self.base.clip = state.clip_stack.last().cloned().unwrap_or_else(max_rect); for mut fragment in self.fragments.fragments.iter_mut() { - let previous_containing_block_scroll_root_id = state.containing_block_scroll_root_id; + let previous_cb_clip_scroll_info = state.containing_block_clip_and_scroll_info; if establishes_containing_block_for_absolute(fragment.style.get_box().position) { - state.containing_block_scroll_root_id = state.current_scroll_root_id; + state.containing_block_clip_and_scroll_info = state.current_clip_and_scroll_info; } match fragment.specific { @@ -2745,14 +2757,14 @@ impl InlineFlowDisplayListBuilding for InlineFlow { &self.base, ScrollPolicy::Scrollable, StackingContextCreationMode::Normal, - state.current_scroll_root_id); + state.current_clip_and_scroll_info); state.add_stacking_context(current_stacking_context_id, stacking_context); } _ => fragment.stacking_context_id = state.current_stacking_context_id, } - state.containing_block_scroll_root_id = previous_containing_block_scroll_root_id; + state.containing_block_clip_and_scroll_info = previous_cb_clip_scroll_info; } } |