Skip to content

Commit

Permalink
Allow inline elements to create reference frames
Browse files Browse the repository at this point in the history
This is important so that transforms applied to elements actually apply
to the display items created for those elements.
  • Loading branch information
mrobinson authored and gw3583 committed Jun 24, 2018
1 parent 2d4b223 commit d41c512
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 19 deletions.
73 changes: 56 additions & 17 deletions components/layout/display_list/builder.rs
Expand Up @@ -576,6 +576,12 @@ pub trait FragmentDisplayListBuilding {
state: &mut StackingContextCollectionState,
) -> 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
/// list if necessary.
fn build_display_list_for_background_if_applicable(
Expand Down Expand Up @@ -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(
&self,
state: &mut DisplayListBuildState,
Expand Down Expand Up @@ -1562,14 +1597,21 @@ impl FragmentDisplayListBuilding for Fragment {
display_list_section: DisplayListSection,
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.build_display_list_no_damage(
state,
stacking_relative_border_box,
border_painting_mode,
display_list_section,
clip,
)
);

state.current_clipping_and_scrolling = previous_clipping_and_scrolling;
}

fn build_display_list_no_damage(
Expand Down Expand Up @@ -2861,8 +2903,11 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
.cloned()
.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() {
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(
StackingContextCollectionFlags::empty(),
fragment.style.get_box().position,
Expand All @@ -2871,26 +2916,20 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
state.current_clipping_and_scrolling;
}

if !fragment.collect_stacking_contexts_for_blocklike_fragment(state) {
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,
);
// We clear this here, but it might be set again if we create a stacking context for
// this fragment.
fragment.established_reference_frame = None;

state.add_stacking_context(current_stacking_context_id, stacking_context);
} else {
if !fragment.collect_stacking_contexts_for_blocklike_fragment(state) {
if !fragment.establishes_stacking_context() {
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;
}
}
Expand Down
11 changes: 10 additions & 1 deletion components/layout/fragment.rs
Expand Up @@ -11,7 +11,7 @@ use app_units::Au;
use canvas_traits::canvas::{CanvasMsg, CanvasId};
use context::{LayoutContext, with_thread_local_font_context};
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 floats::ClearType;
use flow::{GetBaseFlow, ImmutableFlowUtils};
Expand Down Expand Up @@ -152,6 +152,11 @@ pub struct Fragment {
/// to 0, but it assigned during the collect_stacking_contexts phase of display
/// list construction.
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 {
Expand Down Expand Up @@ -633,6 +638,7 @@ impl Fragment {
flags: FragmentFlags::empty(),
debug_id: DebugId::new(),
stacking_context_id: StackingContextId::root(),
established_reference_frame: None,
}
}

Expand Down Expand Up @@ -662,6 +668,7 @@ impl Fragment {
flags: FragmentFlags::empty(),
debug_id: DebugId::new(),
stacking_context_id: StackingContextId::root(),
established_reference_frame: None,
}
}

Expand All @@ -687,6 +694,7 @@ impl Fragment {
flags: FragmentFlags::empty(),
debug_id: DebugId::new(),
stacking_context_id: StackingContextId::root(),
established_reference_frame: None,
}
}

Expand Down Expand Up @@ -715,6 +723,7 @@ impl Fragment {
flags: FragmentFlags::empty(),
debug_id: self.debug_id.clone(),
stacking_context_id: StackingContextId::root(),
established_reference_frame: None,
}
}

Expand Down
2 changes: 1 addition & 1 deletion components/layout/tests/size_of.rs
Expand Up @@ -10,5 +10,5 @@ extern crate layout;
use layout::Fragment;
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);

0 comments on commit d41c512

Please sign in to comment.