Skip to content

Commit a07c718

Browse files
author
bors-servo
authored
Auto merge of servo#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 -->
2 parents eb1dfd0 + 32f00ef commit a07c718

File tree

4 files changed

+160
-50
lines changed

4 files changed

+160
-50
lines changed

components/layout/display_list/builder.rs

Lines changed: 87 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,16 @@ pub struct StackingContextCollectionState {
192192
/// recursively building and processing the display list.
193193
pub current_stacking_context_id: StackingContextId,
194194

195-
/// The current stacking real context id, which doesn't include pseudo-stacking contexts.
195+
/// The current reference frame ClipScrollNodeIndex.
196196
pub current_real_stacking_context_id: StackingContextId,
197197

198198
/// The next stacking context id that we will assign to a stacking context.
199199
pub next_stacking_context_id: StackingContextId,
200200

201+
/// The current reference frame id. This is used to assign items to the parent
202+
/// reference frame when we encounter a fixed position stacking context.
203+
pub current_parent_reference_frame_id: ClipScrollNodeIndex,
204+
201205
/// The current clip and scroll info, used to keep track of state when
202206
/// recursively building and processing the display list.
203207
pub current_clipping_and_scrolling: ClippingAndScrolling,
@@ -221,34 +225,31 @@ pub struct StackingContextCollectionState {
221225

222226
impl StackingContextCollectionState {
223227
pub fn new(pipeline_id: PipelineId) -> StackingContextCollectionState {
224-
let root_clip_indices = ClippingAndScrolling::simple(ClipScrollNodeIndex(0));
225-
226-
// This is just a dummy node to take up a slot in the array. WebRender
227-
// takes care of adding this root node and it can be ignored during DL conversion.
228-
let root_node = ClipScrollNode {
229-
parent_index: ClipScrollNodeIndex(0),
230-
clip: ClippingRegion::from_rect(LayoutRect::zero()),
231-
content_rect: LayoutRect::zero(),
232-
node_type: ClipScrollNodeType::ScrollFrame(
233-
ScrollSensitivity::ScriptAndInputEvents,
234-
pipeline_id.root_scroll_id(),
235-
),
236-
};
228+
let root_clip_indices =
229+
ClippingAndScrolling::simple(ClipScrollNodeIndex::root_scroll_node());
237230

238231
let mut stacking_context_info = FnvHashMap::default();
239232
stacking_context_info.insert(
240233
StackingContextId::root(),
241234
StackingContextInfo::new(StackingContextId::root()),
242235
);
243236

237+
// We add two empty nodes to represent the WebRender root reference frame and
238+
// root scroll nodes. WebRender adds these automatically and we add them here
239+
// so that the ids in the array match up with the ones we assign during display
240+
// list building. We ignore these two nodes during conversion to WebRender
241+
// display lists.
242+
let clip_scroll_nodes = vec![ClipScrollNode::placeholder(), ClipScrollNode::placeholder()];
243+
244244
StackingContextCollectionState {
245245
pipeline_id: pipeline_id,
246246
root_stacking_context: StackingContext::root(),
247247
stacking_context_info,
248-
clip_scroll_nodes: vec![root_node],
248+
clip_scroll_nodes,
249249
current_stacking_context_id: StackingContextId::root(),
250250
current_real_stacking_context_id: StackingContextId::root(),
251251
next_stacking_context_id: StackingContextId::root().next(),
252+
current_parent_reference_frame_id: ClipScrollNodeIndex::root_reference_frame(),
252253
current_clipping_and_scrolling: root_clip_indices,
253254
containing_block_clipping_and_scrolling: root_clip_indices,
254255
clip_stack: Vec::new(),
@@ -291,17 +292,27 @@ impl StackingContextCollectionState {
291292
}
292293

293294
fn add_clip_scroll_node(&mut self, clip_scroll_node: ClipScrollNode) -> ClipScrollNodeIndex {
294-
// We want the scroll root to be defined before any possible item that could use it,
295-
// so we make sure that it is added to the beginning of the parent "real" (non-pseudo)
296-
// stacking context. This ensures that item reordering will not result in an item using
297-
// the scroll root before it is defined.
295+
let is_placeholder = clip_scroll_node.is_placeholder();
296+
298297
self.clip_scroll_nodes.push(clip_scroll_node);
299-
let index = ClipScrollNodeIndex(self.clip_scroll_nodes.len() - 1);
300-
self.stacking_context_info
301-
.get_mut(&self.current_real_stacking_context_id)
302-
.unwrap()
303-
.clip_scroll_nodes
304-
.push(index);
298+
let index = ClipScrollNodeIndex::new(self.clip_scroll_nodes.len() - 1);
299+
300+
// If this node is a placeholder node (currently just reference frames), then don't add
301+
// it to the stacking context list. Placeholder nodes are created automatically by
302+
// WebRender and we don't want to explicitly create them in the display list. The node
303+
// is just there to take up a spot in the global list of ClipScrollNodes.
304+
if !is_placeholder {
305+
// We want the scroll root to be defined before any possible item that could use it,
306+
// so we make sure that it is added to the beginning of the parent "real" (non-pseudo)
307+
// stacking context. This ensures that item reordering will not result in an item using
308+
// the scroll root before it is defined.
309+
self.stacking_context_info
310+
.get_mut(&self.current_real_stacking_context_id)
311+
.unwrap()
312+
.clip_scroll_nodes
313+
.push(index);
314+
}
315+
305316
index
306317
}
307318
}
@@ -347,7 +358,6 @@ impl<'a> DisplayListBuildState<'a> {
347358
layout_context: &'a LayoutContext,
348359
state: StackingContextCollectionState,
349360
) -> DisplayListBuildState<'a> {
350-
let root_clip_indices = ClippingAndScrolling::simple(ClipScrollNodeIndex(0));
351361
DisplayListBuildState {
352362
layout_context: layout_context,
353363
root_stacking_context: state.root_stacking_context,
@@ -356,7 +366,8 @@ impl<'a> DisplayListBuildState<'a> {
356366
clip_scroll_nodes: state.clip_scroll_nodes,
357367
processing_scrolling_overflow_element: false,
358368
current_stacking_context_id: StackingContextId::root(),
359-
current_clipping_and_scrolling: root_clip_indices,
369+
current_clipping_and_scrolling:
370+
ClippingAndScrolling::simple(ClipScrollNodeIndex::root_scroll_node()),
360371
iframe_sizes: Vec::new(),
361372
indexable_text: IndexableText::default(),
362373
}
@@ -374,7 +385,7 @@ impl<'a> DisplayListBuildState<'a> {
374385
return index;
375386
}
376387

377-
self.clip_scroll_nodes[index.0].parent_index
388+
self.clip_scroll_nodes[index.to_index()].parent_index
378389
}
379390

380391
fn is_background_or_border_of_clip_scroll_node(&self, section: DisplayListSection) -> bool {
@@ -429,7 +440,7 @@ impl<'a> DisplayListBuildState<'a> {
429440
// stacking context. This ensures that item reordering will not result in an item using
430441
// the scroll root before it is defined.
431442
self.clip_scroll_nodes.push(node);
432-
let index = ClipScrollNodeIndex(self.clip_scroll_nodes.len() - 1);
443+
let index = ClipScrollNodeIndex::new(self.clip_scroll_nodes.len() - 1);
433444
let real_stacking_context_id =
434445
self.stacking_context_info[&self.current_stacking_context_id].real_stacking_context_id;
435446
self.stacking_context_info
@@ -751,6 +762,7 @@ pub trait FragmentDisplayListBuilding {
751762
base_flow: &BaseFlow,
752763
scroll_policy: ScrollPolicy,
753764
context_type: StackingContextType,
765+
established_reference_frame: Option<ClipScrollNodeIndex>,
754766
parent_clipping_and_scrolling: ClippingAndScrolling,
755767
) -> StackingContext;
756768

@@ -1873,6 +1885,7 @@ impl FragmentDisplayListBuilding for Fragment {
18731885
base_flow: &BaseFlow,
18741886
scroll_policy: ScrollPolicy,
18751887
context_type: StackingContextType,
1888+
established_reference_frame: Option<ClipScrollNodeIndex>,
18761889
parent_clipping_and_scrolling: ClippingAndScrolling,
18771890
) -> StackingContext {
18781891
let border_box = self.stacking_relative_border_box(
@@ -1916,6 +1929,7 @@ impl FragmentDisplayListBuilding for Fragment {
19161929
self.perspective_matrix(&border_box),
19171930
scroll_policy,
19181931
parent_clipping_and_scrolling,
1932+
established_reference_frame,
19191933
)
19201934
}
19211935

@@ -2135,6 +2149,7 @@ pub trait BlockFlowDisplayListBuilding {
21352149
state: &mut StackingContextCollectionState,
21362150
preserved_state: &mut SavedStackingContextCollectionState,
21372151
stacking_context_type: Option<StackingContextType>,
2152+
established_reference_frame: Option<ClipScrollNodeIndex>,
21382153
flags: StackingContextCollectionFlags,
21392154
) -> ClippingAndScrolling;
21402155
fn setup_clip_scroll_node_for_position(
@@ -2164,6 +2179,7 @@ pub trait BlockFlowDisplayListBuilding {
21642179
&mut self,
21652180
parent_stacking_context_id: StackingContextId,
21662181
parent_clipping_and_scrolling: ClippingAndScrolling,
2182+
established_reference_frame: Option<ClipScrollNodeIndex>,
21672183
state: &mut StackingContextCollectionState,
21682184
);
21692185
fn build_display_list_for_block(
@@ -2187,6 +2203,8 @@ pub trait BlockFlowDisplayListBuilding {
21872203
&self,
21882204
flags: StackingContextCollectionFlags,
21892205
) -> Option<StackingContextType>;
2206+
2207+
fn is_reference_frame(&self, context_type: Option<StackingContextType>) -> bool;
21902208
}
21912209

21922210
/// This structure manages ensuring that modification to StackingContextCollectionState is
@@ -2197,6 +2215,7 @@ pub trait BlockFlowDisplayListBuilding {
21972215
pub struct SavedStackingContextCollectionState {
21982216
stacking_context_id: StackingContextId,
21992217
real_stacking_context_id: StackingContextId,
2218+
parent_reference_frame_id: ClipScrollNodeIndex,
22002219
clipping_and_scrolling: ClippingAndScrolling,
22012220
containing_block_clipping_and_scrolling: ClippingAndScrolling,
22022221
clips_pushed: usize,
@@ -2209,6 +2228,7 @@ impl SavedStackingContextCollectionState {
22092228
SavedStackingContextCollectionState {
22102229
stacking_context_id: state.current_stacking_context_id,
22112230
real_stacking_context_id: state.current_real_stacking_context_id,
2231+
parent_reference_frame_id: state.current_parent_reference_frame_id,
22122232
clipping_and_scrolling: state.current_clipping_and_scrolling,
22132233
containing_block_clipping_and_scrolling: state.containing_block_clipping_and_scrolling,
22142234
clips_pushed: 0,
@@ -2230,6 +2250,7 @@ impl SavedStackingContextCollectionState {
22302250
fn restore(self, state: &mut StackingContextCollectionState) {
22312251
state.current_stacking_context_id = self.stacking_context_id;
22322252
state.current_real_stacking_context_id = self.real_stacking_context_id;
2253+
state.current_parent_reference_frame_id = self.parent_reference_frame_id;
22332254
state.current_clipping_and_scrolling = self.clipping_and_scrolling;
22342255
state.containing_block_clipping_and_scrolling =
22352256
self.containing_block_clipping_and_scrolling;
@@ -2332,6 +2353,16 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
23322353
}
23332354
}
23342355

2356+
/// Returns true if this fragment may establish a reference frame and this block
2357+
/// creates a stacking context. Both are necessary in order to establish a reference
2358+
/// frame.
2359+
fn is_reference_frame(&self, context_type: Option<StackingContextType>) -> bool {
2360+
match context_type {
2361+
Some(StackingContextType::Real) => self.fragment.can_establish_reference_frame(),
2362+
_ => false,
2363+
}
2364+
}
2365+
23352366
fn collect_stacking_contexts_for_block(
23362367
&mut self,
23372368
state: &mut StackingContextCollectionState,
@@ -2348,8 +2379,17 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
23482379

23492380
if stacking_context_type == Some(StackingContextType::Real) {
23502381
state.current_real_stacking_context_id = self.base.stacking_context_id;
2382+
23512383
}
23522384

2385+
let established_reference_frame = if self.is_reference_frame(stacking_context_type) {
2386+
// WebRender currently creates reference frames automatically, so just add
2387+
// a placeholder node to allocate a ClipScrollNodeIndex for this reference frame.
2388+
Some(state.add_clip_scroll_node(ClipScrollNode::placeholder()))
2389+
} else {
2390+
None
2391+
};
2392+
23532393
// We are getting the id of the scroll root that contains us here, not the id of
23542394
// any scroll root that we create. If we create a scroll root, its index will be
23552395
// stored in state.current_clipping_and_scrolling. If we create a stacking context,
@@ -2358,6 +2398,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
23582398
state,
23592399
&mut preserved_state,
23602400
stacking_context_type,
2401+
established_reference_frame,
23612402
flags,
23622403
);
23632404

@@ -2371,6 +2412,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
23712412
self.create_real_stacking_context_for_block(
23722413
preserved_state.stacking_context_id,
23732414
containing_clipping_and_scrolling,
2415+
established_reference_frame,
23742416
state,
23752417
);
23762418
},
@@ -2392,6 +2434,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
23922434
state: &mut StackingContextCollectionState,
23932435
preserved_state: &mut SavedStackingContextCollectionState,
23942436
stacking_context_type: Option<StackingContextType>,
2437+
established_reference_frame: Option<ClipScrollNodeIndex>,
23952438
flags: StackingContextCollectionFlags,
23962439
) -> ClippingAndScrolling {
23972440
// If this block is absolutely positioned, we should be clipped and positioned by
@@ -2404,13 +2447,23 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
24042447
state.containing_block_clipping_and_scrolling
24052448
},
24062449
StylePosition::Fixed => {
2450+
// If we are a fixed positioned stacking context, we want to be scrolled by
2451+
// our reference frame instead of the clip scroll node that we are inside.
24072452
preserved_state.push_clip(state, Rect::max_rect(), StylePosition::Fixed);
2453+
state.current_clipping_and_scrolling.scrolling =
2454+
state.current_parent_reference_frame_id;
24082455
state.current_clipping_and_scrolling
24092456
},
24102457
_ => state.current_clipping_and_scrolling,
24112458
};
24122459
self.base.clipping_and_scrolling = Some(containing_clipping_and_scrolling);
24132460

2461+
if let Some(reference_frame_index) = established_reference_frame {
2462+
let clipping_and_scrolling = ClippingAndScrolling::simple(reference_frame_index);
2463+
state.current_clipping_and_scrolling = clipping_and_scrolling;
2464+
self.base.clipping_and_scrolling = Some(clipping_and_scrolling);
2465+
}
2466+
24142467
let stacking_relative_border_box = if self.fragment.establishes_stacking_context() {
24152468
self.stacking_relative_border_box(CoordinateSystem::Own)
24162469
} else {
@@ -2658,6 +2711,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
26582711
&self.base,
26592712
ScrollPolicy::Scrollable,
26602713
stacking_context_type,
2714+
None,
26612715
parent_clipping_and_scrolling,
26622716
);
26632717
state.add_stacking_context(parent_stacking_context_id, new_context);
@@ -2683,19 +2737,15 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
26832737
&mut self,
26842738
parent_stacking_context_id: StackingContextId,
26852739
parent_clipping_and_scrolling: ClippingAndScrolling,
2740+
established_reference_frame: Option<ClipScrollNodeIndex>,
26862741
state: &mut StackingContextCollectionState,
26872742
) {
2688-
let scroll_policy = if self.is_fixed() {
2689-
ScrollPolicy::Fixed
2690-
} else {
2691-
ScrollPolicy::Scrollable
2692-
};
2693-
26942743
let stacking_context = self.fragment.create_stacking_context(
26952744
self.base.stacking_context_id,
26962745
&self.base,
2697-
scroll_policy,
2746+
ScrollPolicy::Scrollable,
26982747
StackingContextType::Real,
2748+
established_reference_frame,
26992749
parent_clipping_and_scrolling,
27002750
);
27012751

@@ -2833,6 +2883,7 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
28332883
&self.base,
28342884
ScrollPolicy::Scrollable,
28352885
StackingContextType::Real,
2886+
None,
28362887
state.current_clipping_and_scrolling,
28372888
);
28382889

0 commit comments

Comments
 (0)