aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2018-06-22 18:13:30 +0200
committerGlenn Watson <github@intuitionlibrary.com>2018-06-25 07:35:10 +1000
commitd41c512e980ea17dc2423f08eb5ccea608e8ca58 (patch)
tree72b14f0205350d6890774ee842524fe3fa870652 /components/layout
parent2d4b223cf48d1b62df4e738db86b707409e3e50e (diff)
downloadservo-d41c512e980ea17dc2423f08eb5ccea608e8ca58.tar.gz
servo-d41c512e980ea17dc2423f08eb5ccea608e8ca58.zip
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.
Diffstat (limited to 'components/layout')
-rw-r--r--components/layout/display_list/builder.rs73
-rw-r--r--components/layout/fragment.rs11
-rw-r--r--components/layout/tests/size_of.rs2
3 files changed, 67 insertions, 19 deletions
diff --git a/components/layout/display_list/builder.rs b/components/layout/display_list/builder.rs
index 2539f648964..5d9a738606e 100644
--- a/components/layout/display_list/builder.rs
+++ b/components/layout/display_list/builder.rs
@@ -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(
@@ -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,
@@ -1562,6 +1597,11 @@ 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,
@@ -1569,7 +1609,9 @@ impl FragmentDisplayListBuilding for Fragment {
border_painting_mode,
display_list_section,
clip,
- )
+ );
+
+ state.current_clipping_and_scrolling = previous_clipping_and_scrolling;
}
fn build_display_list_no_damage(
@@ -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,
@@ -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;
}
}
diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs
index 38ea9d03b93..c3b3ce5fb3e 100644
--- a/components/layout/fragment.rs
+++ b/components/layout/fragment.rs
@@ -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};
@@ -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 {
@@ -633,6 +638,7 @@ impl Fragment {
flags: FragmentFlags::empty(),
debug_id: DebugId::new(),
stacking_context_id: StackingContextId::root(),
+ established_reference_frame: None,
}
}
@@ -662,6 +668,7 @@ impl Fragment {
flags: FragmentFlags::empty(),
debug_id: DebugId::new(),
stacking_context_id: StackingContextId::root(),
+ established_reference_frame: None,
}
}
@@ -687,6 +694,7 @@ impl Fragment {
flags: FragmentFlags::empty(),
debug_id: DebugId::new(),
stacking_context_id: StackingContextId::root(),
+ established_reference_frame: None,
}
}
@@ -715,6 +723,7 @@ impl Fragment {
flags: FragmentFlags::empty(),
debug_id: self.debug_id.clone(),
stacking_context_id: StackingContextId::root(),
+ established_reference_frame: None,
}
}
diff --git a/components/layout/tests/size_of.rs b/components/layout/tests/size_of.rs
index 54b5ef39830..f12b0049f4b 100644
--- a/components/layout/tests/size_of.rs
+++ b/components/layout/tests/size_of.rs
@@ -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);