Allow inline elements to create reference frames

This is important so that transforms applied to elements actually apply
to the display items created for those elements.
This commit is contained in:
Martin Robinson 2018-06-22 18:13:30 +02:00 committed by Glenn Watson
parent 2d4b223cf4
commit d41c512e98
3 changed files with 67 additions and 19 deletions

View file

@ -576,6 +576,12 @@ pub trait FragmentDisplayListBuilding {
state: &mut StackingContextCollectionState, state: &mut StackingContextCollectionState,
) -> bool; ) -> bool;
fn create_stacking_context_for_inline_block(
&mut self,
base: &BaseFlow,
state: &mut StackingContextCollectionState,
) -> bool;
/// Adds the display items necessary to paint the background of this fragment to the display /// Adds the display items necessary to paint the background of this fragment to the display
/// list if necessary. /// list if necessary.
fn build_display_list_for_background_if_applicable( fn build_display_list_for_background_if_applicable(
@ -816,6 +822,35 @@ impl FragmentDisplayListBuilding for Fragment {
} }
} }
fn create_stacking_context_for_inline_block(
&mut self,
base: &BaseFlow,
state: &mut StackingContextCollectionState,
) -> bool {
self.stacking_context_id = state.allocate_stacking_context_info(StackingContextType::Real);
let established_reference_frame = if self.can_establish_reference_frame() {
// WebRender currently creates reference frames automatically, so just add
// a placeholder node to allocate a ClipScrollNodeIndex for this reference frame.
self.established_reference_frame =
Some(state.add_clip_scroll_node(ClipScrollNode::placeholder()));
self.established_reference_frame
} else {
None
};
let current_stacking_context_id = state.current_stacking_context_id;
let stacking_context = self.create_stacking_context(
self.stacking_context_id,
&base,
StackingContextType::Real,
established_reference_frame,
state.current_clipping_and_scrolling,
);
state.add_stacking_context(current_stacking_context_id, stacking_context);
true
}
fn build_display_list_for_background_if_applicable( fn build_display_list_for_background_if_applicable(
&self, &self,
state: &mut DisplayListBuildState, state: &mut DisplayListBuildState,
@ -1562,6 +1597,11 @@ impl FragmentDisplayListBuilding for Fragment {
display_list_section: DisplayListSection, display_list_section: DisplayListSection,
clip: Rect<Au>, clip: Rect<Au>,
) { ) {
let previous_clipping_and_scrolling = state.current_clipping_and_scrolling;
if let Some(index) = self.established_reference_frame {
state.current_clipping_and_scrolling = ClippingAndScrolling::simple(index);
}
self.restyle_damage.remove(ServoRestyleDamage::REPAINT); self.restyle_damage.remove(ServoRestyleDamage::REPAINT);
self.build_display_list_no_damage( self.build_display_list_no_damage(
state, state,
@ -1569,7 +1609,9 @@ impl FragmentDisplayListBuilding for Fragment {
border_painting_mode, border_painting_mode,
display_list_section, display_list_section,
clip, clip,
) );
state.current_clipping_and_scrolling = previous_clipping_and_scrolling;
} }
fn build_display_list_no_damage( fn build_display_list_no_damage(
@ -2861,8 +2903,11 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
.cloned() .cloned()
.unwrap_or_else(Rect::max_rect); .unwrap_or_else(Rect::max_rect);
let previous_cb_clipping_and_scrolling = state.containing_block_clipping_and_scrolling;
for fragment in self.fragments.fragments.iter_mut() { for fragment in self.fragments.fragments.iter_mut() {
let previous_cb_clipping_and_scrolling = state.containing_block_clipping_and_scrolling; state.containing_block_clipping_and_scrolling = previous_cb_clipping_and_scrolling;
if establishes_containing_block_for_absolute( if establishes_containing_block_for_absolute(
StackingContextCollectionFlags::empty(), StackingContextCollectionFlags::empty(),
fragment.style.get_box().position, fragment.style.get_box().position,
@ -2871,26 +2916,20 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
state.current_clipping_and_scrolling; state.current_clipping_and_scrolling;
} }
// We clear this here, but it might be set again if we create a stacking context for
// this fragment.
fragment.established_reference_frame = None;
if !fragment.collect_stacking_contexts_for_blocklike_fragment(state) { if !fragment.collect_stacking_contexts_for_blocklike_fragment(state) {
if fragment.establishes_stacking_context() { if !fragment.establishes_stacking_context() {
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(
fragment.stacking_context_id,
&self.base,
StackingContextType::Real,
None,
state.current_clipping_and_scrolling,
);
state.add_stacking_context(current_stacking_context_id, stacking_context);
} else {
fragment.stacking_context_id = state.current_stacking_context_id; fragment.stacking_context_id = state.current_stacking_context_id;
} else {
fragment.create_stacking_context_for_inline_block(&self.base, state);
} }
} }
// Reset the containing block clipping and scrolling before each loop iteration,
// so we don't pollute subsequent fragments.
state.containing_block_clipping_and_scrolling = previous_cb_clipping_and_scrolling; state.containing_block_clipping_and_scrolling = previous_cb_clipping_and_scrolling;
} }
} }

View file

@ -11,7 +11,7 @@ use app_units::Au;
use canvas_traits::canvas::{CanvasMsg, CanvasId}; use canvas_traits::canvas::{CanvasMsg, CanvasId};
use context::{LayoutContext, with_thread_local_font_context}; use context::{LayoutContext, with_thread_local_font_context};
use display_list::ToLayout; use display_list::ToLayout;
use display_list::items::{BLUR_INFLATION_FACTOR, OpaqueNode}; use display_list::items::{BLUR_INFLATION_FACTOR, ClipScrollNodeIndex, OpaqueNode};
use euclid::{Point2D, Vector2D, Rect, Size2D}; use euclid::{Point2D, Vector2D, Rect, Size2D};
use floats::ClearType; use floats::ClearType;
use flow::{GetBaseFlow, ImmutableFlowUtils}; use flow::{GetBaseFlow, ImmutableFlowUtils};
@ -152,6 +152,11 @@ pub struct Fragment {
/// to 0, but it assigned during the collect_stacking_contexts phase of display /// to 0, but it assigned during the collect_stacking_contexts phase of display
/// list construction. /// list construction.
pub stacking_context_id: StackingContextId, pub stacking_context_id: StackingContextId,
/// The indices of this Fragment's ClipScrollNode. If this fragment doesn't have a
/// `established_reference_frame` assigned, it will use the `clipping_and_scrolling` of the
/// parent block.
pub established_reference_frame: Option<ClipScrollNodeIndex>,
} }
impl Serialize for Fragment { impl Serialize for Fragment {
@ -633,6 +638,7 @@ impl Fragment {
flags: FragmentFlags::empty(), flags: FragmentFlags::empty(),
debug_id: DebugId::new(), debug_id: DebugId::new(),
stacking_context_id: StackingContextId::root(), stacking_context_id: StackingContextId::root(),
established_reference_frame: None,
} }
} }
@ -662,6 +668,7 @@ impl Fragment {
flags: FragmentFlags::empty(), flags: FragmentFlags::empty(),
debug_id: DebugId::new(), debug_id: DebugId::new(),
stacking_context_id: StackingContextId::root(), stacking_context_id: StackingContextId::root(),
established_reference_frame: None,
} }
} }
@ -687,6 +694,7 @@ impl Fragment {
flags: FragmentFlags::empty(), flags: FragmentFlags::empty(),
debug_id: DebugId::new(), debug_id: DebugId::new(),
stacking_context_id: StackingContextId::root(), stacking_context_id: StackingContextId::root(),
established_reference_frame: None,
} }
} }
@ -715,6 +723,7 @@ impl Fragment {
flags: FragmentFlags::empty(), flags: FragmentFlags::empty(),
debug_id: self.debug_id.clone(), debug_id: self.debug_id.clone(),
stacking_context_id: StackingContextId::root(), stacking_context_id: StackingContextId::root(),
established_reference_frame: None,
} }
} }

View file

@ -10,5 +10,5 @@ extern crate layout;
use layout::Fragment; use layout::Fragment;
use layout::SpecificFragmentInfo; use layout::SpecificFragmentInfo;
size_of_test!(test_size_of_fragment, Fragment, 160); size_of_test!(test_size_of_fragment, Fragment, 176);
size_of_test!(test_size_of_specific_fragment_info, SpecificFragmentInfo, 24); size_of_test!(test_size_of_specific_fragment_info, SpecificFragmentInfo, 24);