mirror of
https://github.com/servo/servo.git
synced 2025-07-25 16:20:36 +01:00
Auto merge of #20767 - mrobinson:use-reference-frame-for-fixed-position, r=gw3583
Use reference frames explicitly for fixed positioning <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [x] There are tests for these changes because they should not change behavior. - [ ] These changes do not require tests because _____ <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/20767) <!-- Reviewable:end -->
This commit is contained in:
commit
a07c718895
4 changed files with 160 additions and 50 deletions
|
@ -192,12 +192,16 @@ pub struct StackingContextCollectionState {
|
||||||
/// recursively building and processing the display list.
|
/// recursively building and processing the display list.
|
||||||
pub current_stacking_context_id: StackingContextId,
|
pub current_stacking_context_id: StackingContextId,
|
||||||
|
|
||||||
/// The current stacking real context id, which doesn't include pseudo-stacking contexts.
|
/// The current reference frame ClipScrollNodeIndex.
|
||||||
pub current_real_stacking_context_id: StackingContextId,
|
pub current_real_stacking_context_id: StackingContextId,
|
||||||
|
|
||||||
/// The next stacking context id that we will assign to a stacking context.
|
/// The next stacking context id that we will assign to a stacking context.
|
||||||
pub next_stacking_context_id: StackingContextId,
|
pub next_stacking_context_id: StackingContextId,
|
||||||
|
|
||||||
|
/// The current reference frame id. This is used to assign items to the parent
|
||||||
|
/// reference frame when we encounter a fixed position stacking context.
|
||||||
|
pub current_parent_reference_frame_id: ClipScrollNodeIndex,
|
||||||
|
|
||||||
/// The current clip and scroll info, 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.
|
/// recursively building and processing the display list.
|
||||||
pub current_clipping_and_scrolling: ClippingAndScrolling,
|
pub current_clipping_and_scrolling: ClippingAndScrolling,
|
||||||
|
@ -221,19 +225,8 @@ pub struct StackingContextCollectionState {
|
||||||
|
|
||||||
impl StackingContextCollectionState {
|
impl StackingContextCollectionState {
|
||||||
pub fn new(pipeline_id: PipelineId) -> StackingContextCollectionState {
|
pub fn new(pipeline_id: PipelineId) -> StackingContextCollectionState {
|
||||||
let root_clip_indices = ClippingAndScrolling::simple(ClipScrollNodeIndex(0));
|
let root_clip_indices =
|
||||||
|
ClippingAndScrolling::simple(ClipScrollNodeIndex::root_scroll_node());
|
||||||
// This is just a dummy node to take up a slot in the array. WebRender
|
|
||||||
// takes care of adding this root node and it can be ignored during DL conversion.
|
|
||||||
let root_node = ClipScrollNode {
|
|
||||||
parent_index: ClipScrollNodeIndex(0),
|
|
||||||
clip: ClippingRegion::from_rect(LayoutRect::zero()),
|
|
||||||
content_rect: LayoutRect::zero(),
|
|
||||||
node_type: ClipScrollNodeType::ScrollFrame(
|
|
||||||
ScrollSensitivity::ScriptAndInputEvents,
|
|
||||||
pipeline_id.root_scroll_id(),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut stacking_context_info = FnvHashMap::default();
|
let mut stacking_context_info = FnvHashMap::default();
|
||||||
stacking_context_info.insert(
|
stacking_context_info.insert(
|
||||||
|
@ -241,14 +234,22 @@ impl StackingContextCollectionState {
|
||||||
StackingContextInfo::new(StackingContextId::root()),
|
StackingContextInfo::new(StackingContextId::root()),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// We add two empty nodes to represent the WebRender root reference frame and
|
||||||
|
// root scroll nodes. WebRender adds these automatically and we add them here
|
||||||
|
// so that the ids in the array match up with the ones we assign during display
|
||||||
|
// list building. We ignore these two nodes during conversion to WebRender
|
||||||
|
// display lists.
|
||||||
|
let clip_scroll_nodes = vec![ClipScrollNode::placeholder(), ClipScrollNode::placeholder()];
|
||||||
|
|
||||||
StackingContextCollectionState {
|
StackingContextCollectionState {
|
||||||
pipeline_id: pipeline_id,
|
pipeline_id: pipeline_id,
|
||||||
root_stacking_context: StackingContext::root(),
|
root_stacking_context: StackingContext::root(),
|
||||||
stacking_context_info,
|
stacking_context_info,
|
||||||
clip_scroll_nodes: vec![root_node],
|
clip_scroll_nodes,
|
||||||
current_stacking_context_id: StackingContextId::root(),
|
current_stacking_context_id: StackingContextId::root(),
|
||||||
current_real_stacking_context_id: StackingContextId::root(),
|
current_real_stacking_context_id: StackingContextId::root(),
|
||||||
next_stacking_context_id: StackingContextId::root().next(),
|
next_stacking_context_id: StackingContextId::root().next(),
|
||||||
|
current_parent_reference_frame_id: ClipScrollNodeIndex::root_reference_frame(),
|
||||||
current_clipping_and_scrolling: root_clip_indices,
|
current_clipping_and_scrolling: root_clip_indices,
|
||||||
containing_block_clipping_and_scrolling: root_clip_indices,
|
containing_block_clipping_and_scrolling: root_clip_indices,
|
||||||
clip_stack: Vec::new(),
|
clip_stack: Vec::new(),
|
||||||
|
@ -291,17 +292,27 @@ impl StackingContextCollectionState {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_clip_scroll_node(&mut self, clip_scroll_node: ClipScrollNode) -> ClipScrollNodeIndex {
|
fn add_clip_scroll_node(&mut self, clip_scroll_node: ClipScrollNode) -> ClipScrollNodeIndex {
|
||||||
// We want the scroll root to be defined before any possible item that could use it,
|
let is_placeholder = clip_scroll_node.is_placeholder();
|
||||||
// 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(clip_scroll_node);
|
self.clip_scroll_nodes.push(clip_scroll_node);
|
||||||
let index = ClipScrollNodeIndex(self.clip_scroll_nodes.len() - 1);
|
let index = ClipScrollNodeIndex::new(self.clip_scroll_nodes.len() - 1);
|
||||||
self.stacking_context_info
|
|
||||||
.get_mut(&self.current_real_stacking_context_id)
|
// If this node is a placeholder node (currently just reference frames), then don't add
|
||||||
.unwrap()
|
// it to the stacking context list. Placeholder nodes are created automatically by
|
||||||
.clip_scroll_nodes
|
// WebRender and we don't want to explicitly create them in the display list. The node
|
||||||
.push(index);
|
// is just there to take up a spot in the global list of ClipScrollNodes.
|
||||||
|
if !is_placeholder {
|
||||||
|
// 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.stacking_context_info
|
||||||
|
.get_mut(&self.current_real_stacking_context_id)
|
||||||
|
.unwrap()
|
||||||
|
.clip_scroll_nodes
|
||||||
|
.push(index);
|
||||||
|
}
|
||||||
|
|
||||||
index
|
index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,7 +358,6 @@ impl<'a> DisplayListBuildState<'a> {
|
||||||
layout_context: &'a LayoutContext,
|
layout_context: &'a LayoutContext,
|
||||||
state: StackingContextCollectionState,
|
state: StackingContextCollectionState,
|
||||||
) -> DisplayListBuildState<'a> {
|
) -> DisplayListBuildState<'a> {
|
||||||
let root_clip_indices = ClippingAndScrolling::simple(ClipScrollNodeIndex(0));
|
|
||||||
DisplayListBuildState {
|
DisplayListBuildState {
|
||||||
layout_context: layout_context,
|
layout_context: layout_context,
|
||||||
root_stacking_context: state.root_stacking_context,
|
root_stacking_context: state.root_stacking_context,
|
||||||
|
@ -356,7 +366,8 @@ impl<'a> DisplayListBuildState<'a> {
|
||||||
clip_scroll_nodes: state.clip_scroll_nodes,
|
clip_scroll_nodes: state.clip_scroll_nodes,
|
||||||
processing_scrolling_overflow_element: false,
|
processing_scrolling_overflow_element: false,
|
||||||
current_stacking_context_id: StackingContextId::root(),
|
current_stacking_context_id: StackingContextId::root(),
|
||||||
current_clipping_and_scrolling: root_clip_indices,
|
current_clipping_and_scrolling:
|
||||||
|
ClippingAndScrolling::simple(ClipScrollNodeIndex::root_scroll_node()),
|
||||||
iframe_sizes: Vec::new(),
|
iframe_sizes: Vec::new(),
|
||||||
indexable_text: IndexableText::default(),
|
indexable_text: IndexableText::default(),
|
||||||
}
|
}
|
||||||
|
@ -374,7 +385,7 @@ impl<'a> DisplayListBuildState<'a> {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.clip_scroll_nodes[index.0].parent_index
|
self.clip_scroll_nodes[index.to_index()].parent_index
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_background_or_border_of_clip_scroll_node(&self, section: DisplayListSection) -> bool {
|
fn is_background_or_border_of_clip_scroll_node(&self, section: DisplayListSection) -> bool {
|
||||||
|
@ -429,7 +440,7 @@ impl<'a> DisplayListBuildState<'a> {
|
||||||
// stacking context. This ensures that item reordering will not result in an item using
|
// stacking context. This ensures that item reordering will not result in an item using
|
||||||
// the scroll root before it is defined.
|
// the scroll root before it is defined.
|
||||||
self.clip_scroll_nodes.push(node);
|
self.clip_scroll_nodes.push(node);
|
||||||
let index = ClipScrollNodeIndex(self.clip_scroll_nodes.len() - 1);
|
let index = ClipScrollNodeIndex::new(self.clip_scroll_nodes.len() - 1);
|
||||||
let real_stacking_context_id =
|
let real_stacking_context_id =
|
||||||
self.stacking_context_info[&self.current_stacking_context_id].real_stacking_context_id;
|
self.stacking_context_info[&self.current_stacking_context_id].real_stacking_context_id;
|
||||||
self.stacking_context_info
|
self.stacking_context_info
|
||||||
|
@ -751,6 +762,7 @@ pub trait FragmentDisplayListBuilding {
|
||||||
base_flow: &BaseFlow,
|
base_flow: &BaseFlow,
|
||||||
scroll_policy: ScrollPolicy,
|
scroll_policy: ScrollPolicy,
|
||||||
context_type: StackingContextType,
|
context_type: StackingContextType,
|
||||||
|
established_reference_frame: Option<ClipScrollNodeIndex>,
|
||||||
parent_clipping_and_scrolling: ClippingAndScrolling,
|
parent_clipping_and_scrolling: ClippingAndScrolling,
|
||||||
) -> StackingContext;
|
) -> StackingContext;
|
||||||
|
|
||||||
|
@ -1873,6 +1885,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
base_flow: &BaseFlow,
|
base_flow: &BaseFlow,
|
||||||
scroll_policy: ScrollPolicy,
|
scroll_policy: ScrollPolicy,
|
||||||
context_type: StackingContextType,
|
context_type: StackingContextType,
|
||||||
|
established_reference_frame: Option<ClipScrollNodeIndex>,
|
||||||
parent_clipping_and_scrolling: ClippingAndScrolling,
|
parent_clipping_and_scrolling: ClippingAndScrolling,
|
||||||
) -> StackingContext {
|
) -> StackingContext {
|
||||||
let border_box = self.stacking_relative_border_box(
|
let border_box = self.stacking_relative_border_box(
|
||||||
|
@ -1916,6 +1929,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
self.perspective_matrix(&border_box),
|
self.perspective_matrix(&border_box),
|
||||||
scroll_policy,
|
scroll_policy,
|
||||||
parent_clipping_and_scrolling,
|
parent_clipping_and_scrolling,
|
||||||
|
established_reference_frame,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2135,6 +2149,7 @@ pub trait BlockFlowDisplayListBuilding {
|
||||||
state: &mut StackingContextCollectionState,
|
state: &mut StackingContextCollectionState,
|
||||||
preserved_state: &mut SavedStackingContextCollectionState,
|
preserved_state: &mut SavedStackingContextCollectionState,
|
||||||
stacking_context_type: Option<StackingContextType>,
|
stacking_context_type: Option<StackingContextType>,
|
||||||
|
established_reference_frame: Option<ClipScrollNodeIndex>,
|
||||||
flags: StackingContextCollectionFlags,
|
flags: StackingContextCollectionFlags,
|
||||||
) -> ClippingAndScrolling;
|
) -> ClippingAndScrolling;
|
||||||
fn setup_clip_scroll_node_for_position(
|
fn setup_clip_scroll_node_for_position(
|
||||||
|
@ -2164,6 +2179,7 @@ pub trait BlockFlowDisplayListBuilding {
|
||||||
&mut self,
|
&mut self,
|
||||||
parent_stacking_context_id: StackingContextId,
|
parent_stacking_context_id: StackingContextId,
|
||||||
parent_clipping_and_scrolling: ClippingAndScrolling,
|
parent_clipping_and_scrolling: ClippingAndScrolling,
|
||||||
|
established_reference_frame: Option<ClipScrollNodeIndex>,
|
||||||
state: &mut StackingContextCollectionState,
|
state: &mut StackingContextCollectionState,
|
||||||
);
|
);
|
||||||
fn build_display_list_for_block(
|
fn build_display_list_for_block(
|
||||||
|
@ -2187,6 +2203,8 @@ pub trait BlockFlowDisplayListBuilding {
|
||||||
&self,
|
&self,
|
||||||
flags: StackingContextCollectionFlags,
|
flags: StackingContextCollectionFlags,
|
||||||
) -> Option<StackingContextType>;
|
) -> Option<StackingContextType>;
|
||||||
|
|
||||||
|
fn is_reference_frame(&self, context_type: Option<StackingContextType>) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This structure manages ensuring that modification to StackingContextCollectionState is
|
/// This structure manages ensuring that modification to StackingContextCollectionState is
|
||||||
|
@ -2197,6 +2215,7 @@ pub trait BlockFlowDisplayListBuilding {
|
||||||
pub struct SavedStackingContextCollectionState {
|
pub struct SavedStackingContextCollectionState {
|
||||||
stacking_context_id: StackingContextId,
|
stacking_context_id: StackingContextId,
|
||||||
real_stacking_context_id: StackingContextId,
|
real_stacking_context_id: StackingContextId,
|
||||||
|
parent_reference_frame_id: ClipScrollNodeIndex,
|
||||||
clipping_and_scrolling: ClippingAndScrolling,
|
clipping_and_scrolling: ClippingAndScrolling,
|
||||||
containing_block_clipping_and_scrolling: ClippingAndScrolling,
|
containing_block_clipping_and_scrolling: ClippingAndScrolling,
|
||||||
clips_pushed: usize,
|
clips_pushed: usize,
|
||||||
|
@ -2209,6 +2228,7 @@ impl SavedStackingContextCollectionState {
|
||||||
SavedStackingContextCollectionState {
|
SavedStackingContextCollectionState {
|
||||||
stacking_context_id: state.current_stacking_context_id,
|
stacking_context_id: state.current_stacking_context_id,
|
||||||
real_stacking_context_id: state.current_real_stacking_context_id,
|
real_stacking_context_id: state.current_real_stacking_context_id,
|
||||||
|
parent_reference_frame_id: state.current_parent_reference_frame_id,
|
||||||
clipping_and_scrolling: state.current_clipping_and_scrolling,
|
clipping_and_scrolling: state.current_clipping_and_scrolling,
|
||||||
containing_block_clipping_and_scrolling: state.containing_block_clipping_and_scrolling,
|
containing_block_clipping_and_scrolling: state.containing_block_clipping_and_scrolling,
|
||||||
clips_pushed: 0,
|
clips_pushed: 0,
|
||||||
|
@ -2230,6 +2250,7 @@ impl SavedStackingContextCollectionState {
|
||||||
fn restore(self, state: &mut StackingContextCollectionState) {
|
fn restore(self, state: &mut StackingContextCollectionState) {
|
||||||
state.current_stacking_context_id = self.stacking_context_id;
|
state.current_stacking_context_id = self.stacking_context_id;
|
||||||
state.current_real_stacking_context_id = self.real_stacking_context_id;
|
state.current_real_stacking_context_id = self.real_stacking_context_id;
|
||||||
|
state.current_parent_reference_frame_id = self.parent_reference_frame_id;
|
||||||
state.current_clipping_and_scrolling = self.clipping_and_scrolling;
|
state.current_clipping_and_scrolling = self.clipping_and_scrolling;
|
||||||
state.containing_block_clipping_and_scrolling =
|
state.containing_block_clipping_and_scrolling =
|
||||||
self.containing_block_clipping_and_scrolling;
|
self.containing_block_clipping_and_scrolling;
|
||||||
|
@ -2332,6 +2353,16 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if this fragment may establish a reference frame and this block
|
||||||
|
/// creates a stacking context. Both are necessary in order to establish a reference
|
||||||
|
/// frame.
|
||||||
|
fn is_reference_frame(&self, context_type: Option<StackingContextType>) -> bool {
|
||||||
|
match context_type {
|
||||||
|
Some(StackingContextType::Real) => self.fragment.can_establish_reference_frame(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn collect_stacking_contexts_for_block(
|
fn collect_stacking_contexts_for_block(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut StackingContextCollectionState,
|
state: &mut StackingContextCollectionState,
|
||||||
|
@ -2348,8 +2379,17 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||||
|
|
||||||
if stacking_context_type == Some(StackingContextType::Real) {
|
if stacking_context_type == Some(StackingContextType::Real) {
|
||||||
state.current_real_stacking_context_id = self.base.stacking_context_id;
|
state.current_real_stacking_context_id = self.base.stacking_context_id;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let established_reference_frame = if self.is_reference_frame(stacking_context_type) {
|
||||||
|
// WebRender currently creates reference frames automatically, so just add
|
||||||
|
// a placeholder node to allocate a ClipScrollNodeIndex for this reference frame.
|
||||||
|
Some(state.add_clip_scroll_node(ClipScrollNode::placeholder()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// We are getting the id of the scroll root that contains us here, not the id of
|
// 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 index will be
|
// any scroll root that we create. If we create a scroll root, its index will be
|
||||||
// stored in state.current_clipping_and_scrolling. If we create a stacking context,
|
// stored in state.current_clipping_and_scrolling. If we create a stacking context,
|
||||||
|
@ -2358,6 +2398,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||||
state,
|
state,
|
||||||
&mut preserved_state,
|
&mut preserved_state,
|
||||||
stacking_context_type,
|
stacking_context_type,
|
||||||
|
established_reference_frame,
|
||||||
flags,
|
flags,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2371,6 +2412,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||||
self.create_real_stacking_context_for_block(
|
self.create_real_stacking_context_for_block(
|
||||||
preserved_state.stacking_context_id,
|
preserved_state.stacking_context_id,
|
||||||
containing_clipping_and_scrolling,
|
containing_clipping_and_scrolling,
|
||||||
|
established_reference_frame,
|
||||||
state,
|
state,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -2392,6 +2434,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||||
state: &mut StackingContextCollectionState,
|
state: &mut StackingContextCollectionState,
|
||||||
preserved_state: &mut SavedStackingContextCollectionState,
|
preserved_state: &mut SavedStackingContextCollectionState,
|
||||||
stacking_context_type: Option<StackingContextType>,
|
stacking_context_type: Option<StackingContextType>,
|
||||||
|
established_reference_frame: Option<ClipScrollNodeIndex>,
|
||||||
flags: StackingContextCollectionFlags,
|
flags: StackingContextCollectionFlags,
|
||||||
) -> ClippingAndScrolling {
|
) -> ClippingAndScrolling {
|
||||||
// If this block is absolutely positioned, we should be clipped and positioned by
|
// If this block is absolutely positioned, we should be clipped and positioned by
|
||||||
|
@ -2404,13 +2447,23 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||||
state.containing_block_clipping_and_scrolling
|
state.containing_block_clipping_and_scrolling
|
||||||
},
|
},
|
||||||
StylePosition::Fixed => {
|
StylePosition::Fixed => {
|
||||||
|
// If we are a fixed positioned stacking context, we want to be scrolled by
|
||||||
|
// our reference frame instead of the clip scroll node that we are inside.
|
||||||
preserved_state.push_clip(state, Rect::max_rect(), StylePosition::Fixed);
|
preserved_state.push_clip(state, Rect::max_rect(), StylePosition::Fixed);
|
||||||
|
state.current_clipping_and_scrolling.scrolling =
|
||||||
|
state.current_parent_reference_frame_id;
|
||||||
state.current_clipping_and_scrolling
|
state.current_clipping_and_scrolling
|
||||||
},
|
},
|
||||||
_ => state.current_clipping_and_scrolling,
|
_ => state.current_clipping_and_scrolling,
|
||||||
};
|
};
|
||||||
self.base.clipping_and_scrolling = Some(containing_clipping_and_scrolling);
|
self.base.clipping_and_scrolling = Some(containing_clipping_and_scrolling);
|
||||||
|
|
||||||
|
if let Some(reference_frame_index) = established_reference_frame {
|
||||||
|
let clipping_and_scrolling = ClippingAndScrolling::simple(reference_frame_index);
|
||||||
|
state.current_clipping_and_scrolling = clipping_and_scrolling;
|
||||||
|
self.base.clipping_and_scrolling = Some(clipping_and_scrolling);
|
||||||
|
}
|
||||||
|
|
||||||
let stacking_relative_border_box = if self.fragment.establishes_stacking_context() {
|
let stacking_relative_border_box = if self.fragment.establishes_stacking_context() {
|
||||||
self.stacking_relative_border_box(CoordinateSystem::Own)
|
self.stacking_relative_border_box(CoordinateSystem::Own)
|
||||||
} else {
|
} else {
|
||||||
|
@ -2658,6 +2711,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||||
&self.base,
|
&self.base,
|
||||||
ScrollPolicy::Scrollable,
|
ScrollPolicy::Scrollable,
|
||||||
stacking_context_type,
|
stacking_context_type,
|
||||||
|
None,
|
||||||
parent_clipping_and_scrolling,
|
parent_clipping_and_scrolling,
|
||||||
);
|
);
|
||||||
state.add_stacking_context(parent_stacking_context_id, new_context);
|
state.add_stacking_context(parent_stacking_context_id, new_context);
|
||||||
|
@ -2683,19 +2737,15 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||||
&mut self,
|
&mut self,
|
||||||
parent_stacking_context_id: StackingContextId,
|
parent_stacking_context_id: StackingContextId,
|
||||||
parent_clipping_and_scrolling: ClippingAndScrolling,
|
parent_clipping_and_scrolling: ClippingAndScrolling,
|
||||||
|
established_reference_frame: Option<ClipScrollNodeIndex>,
|
||||||
state: &mut StackingContextCollectionState,
|
state: &mut StackingContextCollectionState,
|
||||||
) {
|
) {
|
||||||
let scroll_policy = if self.is_fixed() {
|
|
||||||
ScrollPolicy::Fixed
|
|
||||||
} else {
|
|
||||||
ScrollPolicy::Scrollable
|
|
||||||
};
|
|
||||||
|
|
||||||
let stacking_context = self.fragment.create_stacking_context(
|
let stacking_context = self.fragment.create_stacking_context(
|
||||||
self.base.stacking_context_id,
|
self.base.stacking_context_id,
|
||||||
&self.base,
|
&self.base,
|
||||||
scroll_policy,
|
ScrollPolicy::Scrollable,
|
||||||
StackingContextType::Real,
|
StackingContextType::Real,
|
||||||
|
established_reference_frame,
|
||||||
parent_clipping_and_scrolling,
|
parent_clipping_and_scrolling,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2833,6 +2883,7 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
|
||||||
&self.base,
|
&self.base,
|
||||||
ScrollPolicy::Scrollable,
|
ScrollPolicy::Scrollable,
|
||||||
StackingContextType::Real,
|
StackingContextType::Real,
|
||||||
|
None,
|
||||||
state.current_clipping_and_scrolling,
|
state.current_clipping_and_scrolling,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -38,14 +38,25 @@ pub static BLUR_INFLATION_FACTOR: i32 = 3;
|
||||||
/// An index into the vector of ClipScrollNodes. During WebRender conversion these nodes
|
/// An index into the vector of ClipScrollNodes. During WebRender conversion these nodes
|
||||||
/// are given ClipIds.
|
/// are given ClipIds.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
|
||||||
pub struct ClipScrollNodeIndex(pub usize);
|
pub struct ClipScrollNodeIndex(usize);
|
||||||
|
|
||||||
impl ClipScrollNodeIndex {
|
impl ClipScrollNodeIndex {
|
||||||
|
pub fn root_scroll_node() -> ClipScrollNodeIndex {
|
||||||
|
ClipScrollNodeIndex(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn root_reference_frame() -> ClipScrollNodeIndex {
|
||||||
|
ClipScrollNodeIndex(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(index: usize) -> ClipScrollNodeIndex {
|
||||||
|
assert_ne!(index, 0, "Use the root_reference_frame constructor");
|
||||||
|
assert_ne!(index, 1, "Use the root_scroll_node constructor");
|
||||||
|
ClipScrollNodeIndex(index)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_root_scroll_node(&self) -> bool {
|
pub fn is_root_scroll_node(&self) -> bool {
|
||||||
match *self {
|
*self == Self::root_scroll_node()
|
||||||
ClipScrollNodeIndex(0) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_define_item(&self) -> DisplayItem {
|
pub fn to_define_item(&self) -> DisplayItem {
|
||||||
|
@ -54,6 +65,10 @@ impl ClipScrollNodeIndex {
|
||||||
node_index: *self,
|
node_index: *self,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_index(self) -> usize {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A set of indices into the clip scroll node vector for a given item.
|
/// A set of indices into the clip scroll node vector for a given item.
|
||||||
|
@ -193,6 +208,9 @@ pub struct StackingContext {
|
||||||
|
|
||||||
/// The clip and scroll info for this StackingContext.
|
/// The clip and scroll info for this StackingContext.
|
||||||
pub parent_clipping_and_scrolling: ClippingAndScrolling,
|
pub parent_clipping_and_scrolling: ClippingAndScrolling,
|
||||||
|
|
||||||
|
/// The index of the reference frame that this stacking context estalishes.
|
||||||
|
pub established_reference_frame: Option<ClipScrollNodeIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StackingContext {
|
impl StackingContext {
|
||||||
|
@ -211,6 +229,7 @@ impl StackingContext {
|
||||||
perspective: Option<LayoutTransform>,
|
perspective: Option<LayoutTransform>,
|
||||||
scroll_policy: ScrollPolicy,
|
scroll_policy: ScrollPolicy,
|
||||||
parent_clipping_and_scrolling: ClippingAndScrolling,
|
parent_clipping_and_scrolling: ClippingAndScrolling,
|
||||||
|
established_reference_frame: Option<ClipScrollNodeIndex>,
|
||||||
) -> StackingContext {
|
) -> StackingContext {
|
||||||
StackingContext {
|
StackingContext {
|
||||||
id,
|
id,
|
||||||
|
@ -225,6 +244,7 @@ impl StackingContext {
|
||||||
perspective,
|
perspective,
|
||||||
scroll_policy,
|
scroll_policy,
|
||||||
parent_clipping_and_scrolling,
|
parent_clipping_and_scrolling,
|
||||||
|
established_reference_frame,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +262,8 @@ impl StackingContext {
|
||||||
TransformStyle::Flat,
|
TransformStyle::Flat,
|
||||||
None,
|
None,
|
||||||
ScrollPolicy::Scrollable,
|
ScrollPolicy::Scrollable,
|
||||||
ClippingAndScrolling::simple(ClipScrollNodeIndex(0)),
|
ClippingAndScrolling::simple(ClipScrollNodeIndex::root_scroll_node()),
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,15 +330,16 @@ impl fmt::Debug for StackingContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize)]
|
||||||
pub struct StickyFrameData {
|
pub struct StickyFrameData {
|
||||||
pub margins: SideOffsets2D<Option<f32>>,
|
pub margins: SideOffsets2D<Option<f32>>,
|
||||||
pub vertical_offset_bounds: StickyOffsetBounds,
|
pub vertical_offset_bounds: StickyOffsetBounds,
|
||||||
pub horizontal_offset_bounds: StickyOffsetBounds,
|
pub horizontal_offset_bounds: StickyOffsetBounds,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize)]
|
||||||
pub enum ClipScrollNodeType {
|
pub enum ClipScrollNodeType {
|
||||||
|
Placeholder,
|
||||||
ScrollFrame(ScrollSensitivity, ExternalScrollId),
|
ScrollFrame(ScrollSensitivity, ExternalScrollId),
|
||||||
StickyFrame(StickyFrameData),
|
StickyFrame(StickyFrameData),
|
||||||
Clip,
|
Clip,
|
||||||
|
@ -339,6 +361,21 @@ pub struct ClipScrollNode {
|
||||||
pub node_type: ClipScrollNodeType,
|
pub node_type: ClipScrollNodeType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ClipScrollNode {
|
||||||
|
pub fn placeholder() -> ClipScrollNode {
|
||||||
|
ClipScrollNode {
|
||||||
|
parent_index: ClipScrollNodeIndex(0),
|
||||||
|
clip: ClippingRegion::from_rect(LayoutRect::zero()),
|
||||||
|
content_rect: LayoutRect::zero(),
|
||||||
|
node_type: ClipScrollNodeType::Placeholder,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_placeholder(&self) -> bool {
|
||||||
|
self.node_type == ClipScrollNodeType::Placeholder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// One drawing command in the list.
|
/// One drawing command in the list.
|
||||||
#[derive(Clone, Serialize)]
|
#[derive(Clone, Serialize)]
|
||||||
pub enum DisplayItem {
|
pub enum DisplayItem {
|
||||||
|
@ -412,7 +449,8 @@ impl BaseDisplayItem {
|
||||||
clip_rect: LayoutRect::max_rect(),
|
clip_rect: LayoutRect::max_rect(),
|
||||||
section: DisplayListSection::Content,
|
section: DisplayListSection::Content,
|
||||||
stacking_context_id: StackingContextId::root(),
|
stacking_context_id: StackingContextId::root(),
|
||||||
clipping_and_scrolling: ClippingAndScrolling::simple(ClipScrollNodeIndex(0)),
|
clipping_and_scrolling:
|
||||||
|
ClippingAndScrolling::simple(ClipScrollNodeIndex::root_scroll_node()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,12 @@ impl WebRenderDisplayListConverter for DisplayList {
|
||||||
|
|
||||||
let mut clip_ids = Vec::with_capacity(self.clip_scroll_nodes.len());
|
let mut clip_ids = Vec::with_capacity(self.clip_scroll_nodes.len());
|
||||||
clip_ids.resize(self.clip_scroll_nodes.len(), None);
|
clip_ids.resize(self.clip_scroll_nodes.len(), None);
|
||||||
clip_ids[0] = Some(ClipId::root_scroll_node(pipeline_id.to_webrender()));
|
|
||||||
|
// We need to add the WebRender root reference frame and root scroll node ids
|
||||||
|
// here manually, because WebRender creates these automatically.
|
||||||
|
let webrender_pipeline = pipeline_id.to_webrender();
|
||||||
|
clip_ids[0] = Some(ClipId::root_reference_frame(webrender_pipeline));
|
||||||
|
clip_ids[1] = Some(ClipId::root_scroll_node(webrender_pipeline));
|
||||||
|
|
||||||
for item in &self.list {
|
for item in &self.list {
|
||||||
item.convert_to_webrender(
|
item.convert_to_webrender(
|
||||||
|
@ -78,7 +83,7 @@ impl WebRenderDisplayItemConverter for DisplayItem {
|
||||||
current_clip_and_scroll_info: &mut ClipAndScrollInfo,
|
current_clip_and_scroll_info: &mut ClipAndScrollInfo,
|
||||||
) {
|
) {
|
||||||
let get_id = |clip_ids: &[Option<ClipId>], index: ClipScrollNodeIndex| -> ClipId {
|
let get_id = |clip_ids: &[Option<ClipId>], index: ClipScrollNodeIndex| -> ClipId {
|
||||||
match clip_ids[index.0] {
|
match clip_ids[index.to_index()] {
|
||||||
Some(id) => id,
|
Some(id) => id,
|
||||||
None => unreachable!("Tried to use WebRender ClipId before it was defined."),
|
None => unreachable!("Tried to use WebRender ClipId before it was defined."),
|
||||||
}
|
}
|
||||||
|
@ -214,7 +219,7 @@ impl WebRenderDisplayItemConverter for DisplayItem {
|
||||||
let stacking_context = &item.stacking_context;
|
let stacking_context = &item.stacking_context;
|
||||||
debug_assert_eq!(stacking_context.context_type, StackingContextType::Real);
|
debug_assert_eq!(stacking_context.context_type, StackingContextType::Real);
|
||||||
|
|
||||||
builder.push_stacking_context(
|
let reference_frame_clip_id = builder.push_stacking_context(
|
||||||
&webrender_api::LayoutPrimitiveInfo::new(stacking_context.bounds),
|
&webrender_api::LayoutPrimitiveInfo::new(stacking_context.bounds),
|
||||||
None,
|
None,
|
||||||
stacking_context.scroll_policy,
|
stacking_context.scroll_policy,
|
||||||
|
@ -225,10 +230,17 @@ impl WebRenderDisplayItemConverter for DisplayItem {
|
||||||
stacking_context.filters.clone(),
|
stacking_context.filters.clone(),
|
||||||
GlyphRasterSpace::Screen,
|
GlyphRasterSpace::Screen,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
match (reference_frame_clip_id, stacking_context.established_reference_frame) {
|
||||||
|
(Some(webrender_id), Some(frame_index)) =>
|
||||||
|
clip_ids[frame_index.to_index()] = Some(webrender_id),
|
||||||
|
(None, None) => {},
|
||||||
|
_ => warn!("Mismatch between reference frame establishment!"),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
DisplayItem::PopStackingContext(_) => builder.pop_stacking_context(),
|
DisplayItem::PopStackingContext(_) => builder.pop_stacking_context(),
|
||||||
DisplayItem::DefineClipScrollNode(ref item) => {
|
DisplayItem::DefineClipScrollNode(ref item) => {
|
||||||
let node = &clip_scroll_nodes[item.node_index.0];
|
let node = &clip_scroll_nodes[item.node_index.to_index()];
|
||||||
let parent_id = get_id(clip_ids, node.parent_index);
|
let parent_id = get_id(clip_ids, node.parent_index);
|
||||||
let item_rect = node.clip.main;
|
let item_rect = node.clip.main;
|
||||||
|
|
||||||
|
@ -262,9 +274,12 @@ impl WebRenderDisplayItemConverter for DisplayItem {
|
||||||
builder.pop_clip_id();
|
builder.pop_clip_id();
|
||||||
id
|
id
|
||||||
},
|
},
|
||||||
|
ClipScrollNodeType::Placeholder => {
|
||||||
|
unreachable!("Found DefineClipScrollNode for Placeholder type node.");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
clip_ids[item.node_index.0] = Some(webrender_id);
|
clip_ids[item.node_index.to_index()] = Some(webrender_id);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2474,6 +2474,12 @@ impl Fragment {
|
||||||
stacking_relative_border_box.size.height - border_padding.vertical()))
|
stacking_relative_border_box.size.height - border_padding.vertical()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if this fragment may establish a reference frame.
|
||||||
|
pub fn can_establish_reference_frame(&self) -> bool {
|
||||||
|
!self.style().get_box().transform.0.is_empty() ||
|
||||||
|
self.style().get_box().perspective != Perspective::None
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if this fragment has a filter, transform, or perspective property set.
|
/// Returns true if this fragment has a filter, transform, or perspective property set.
|
||||||
pub fn has_filter_transform_or_perspective(&self) -> bool {
|
pub fn has_filter_transform_or_perspective(&self) -> bool {
|
||||||
!self.style().get_box().transform.0.is_empty() ||
|
!self.style().get_box().transform.0.is_empty() ||
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue