@@ -543,6 +543,12 @@ pub struct SceneBuilder<'a> {
543
543
544
544
/// Used to build a ClipTree from the clip-chains, clips and state during scene building.
545
545
clip_tree_builder : ClipTreeBuilder ,
546
+
547
+ /// Some primitives need to nest two stacking contexts instead of one
548
+ /// (see push_stacking_context). We keep track of the extra stacking context info
549
+ /// here and set a boolean on the inner stacking context info to remember to
550
+ /// pop from this stack (see StackingContextInfo::needs_extra_stacking_context)
551
+ extra_stacking_context_stack : Vec < StackingContextInfo > ,
546
552
}
547
553
548
554
impl < ' a > SceneBuilder < ' a > {
@@ -602,6 +608,7 @@ impl<'a> SceneBuilder<'a> {
602
608
pipeline_instance_ids : FastHashMap :: default ( ) ,
603
609
surfaces : mem:: take ( & mut recycler. surfaces ) ,
604
610
clip_tree_builder : recycler. clip_tree_builder . take ( ) . unwrap_or_else ( || ClipTreeBuilder :: new ( ) ) ,
611
+ extra_stacking_context_stack : Vec :: new ( ) ,
605
612
} ;
606
613
607
614
// Reset
@@ -2150,17 +2157,50 @@ impl<'a> SceneBuilder<'a> {
2150
2157
/// Push a new stacking context. Returns context that must be passed to pop_stacking_context().
2151
2158
fn push_stacking_context (
2152
2159
& mut self ,
2153
- composite_ops : CompositeOps ,
2160
+ mut composite_ops : CompositeOps ,
2154
2161
transform_style : TransformStyle ,
2155
2162
prim_flags : PrimitiveFlags ,
2156
2163
spatial_node_index : SpatialNodeIndex ,
2157
- clip_chain_id : Option < api:: ClipChainId > ,
2164
+ mut clip_chain_id : Option < api:: ClipChainId > ,
2158
2165
requested_raster_space : RasterSpace ,
2159
2166
flags : StackingContextFlags ,
2160
2167
subregion_offset : LayoutVector2D ,
2161
2168
) -> StackingContextInfo {
2162
2169
profile_scope ! ( "push_stacking_context" ) ;
2163
2170
2171
+ // Filters have to be baked into the snapshot. Most filters are applied
2172
+ // when rendering the picture into its parent, so if the stacking context
2173
+ // needs to be snapshotted, we nest it into an extra stacking context and
2174
+ // capture the outer stacking context into which the filter is drawn.
2175
+ // Note: blur filters don't actually need an extra stacking context
2176
+ // since the blur is baked into a render task instead of being applied
2177
+ // when compositing the picture into its parent. This case is fairly rare
2178
+ // so we pay the cost of the extra render pass for now.
2179
+ let needs_extra_stacking_context = composite_ops. snapshot . is_some ( )
2180
+ && composite_ops. has_valid_filters ( ) ;
2181
+
2182
+ if needs_extra_stacking_context {
2183
+ let snapshot = mem:: take ( & mut composite_ops. snapshot ) ;
2184
+ let mut info = self . push_stacking_context (
2185
+ CompositeOps {
2186
+ filters : Vec :: new ( ) ,
2187
+ filter_datas : Vec :: new ( ) ,
2188
+ filter_primitives : Vec :: new ( ) ,
2189
+ mix_blend_mode : None ,
2190
+ snapshot,
2191
+ } ,
2192
+ TransformStyle :: Flat ,
2193
+ prim_flags,
2194
+ spatial_node_index,
2195
+ clip_chain_id. take ( ) ,
2196
+ requested_raster_space,
2197
+ flags,
2198
+ LayoutVector2D :: zero ( ) ,
2199
+ ) ;
2200
+ info. pop_stacking_context = true ;
2201
+ self . extra_stacking_context_stack . push ( info) ;
2202
+ }
2203
+
2164
2204
let clip_node_id = match clip_chain_id {
2165
2205
Some ( id) => {
2166
2206
self . clip_tree_builder . build_clip_set ( id)
@@ -2342,6 +2382,7 @@ impl<'a> SceneBuilder<'a> {
2342
2382
pop_stacking_context : false ,
2343
2383
pop_containing_block : false ,
2344
2384
set_tile_cache_barrier,
2385
+ needs_extra_stacking_context,
2345
2386
} ;
2346
2387
2347
2388
// If this is not 3d, then it establishes an ancestor root for child 3d contexts.
@@ -2699,6 +2740,11 @@ impl<'a> SceneBuilder<'a> {
2699
2740
self . pending_shadow_items. is_empty( ) ,
2700
2741
"Found unpopped shadows when popping stacking context!"
2701
2742
) ;
2743
+
2744
+ if info. needs_extra_stacking_context {
2745
+ let inner_info = self . extra_stacking_context_stack . pop ( ) . unwrap ( ) ;
2746
+ self . pop_stacking_context ( inner_info) ;
2747
+ }
2702
2748
}
2703
2749
2704
2750
pub fn push_reference_frame (
@@ -4498,6 +4544,10 @@ struct StackingContextInfo {
4498
4544
pop_stacking_context : bool ,
4499
4545
/// If true, set a tile cache barrier when popping the stacking context.
4500
4546
set_tile_cache_barrier : bool ,
4547
+ /// If true, this stacking context was nested into two pushes instead of
4548
+ /// one, and requires an extra pop to compensate. The info to pop is stored
4549
+ /// at the top of `extra_stacking_context_stack`.
4550
+ needs_extra_stacking_context : bool ,
4501
4551
}
4502
4552
4503
4553
/// Properties of a stacking context that are maintained
0 commit comments