@ -2,12 +2,15 @@
* License , v . 2. 0. If a copy of the MPL was not distributed with this
* License , v . 2. 0. If a copy of the MPL was not distributed with this
* file , You can obtain one at https ://mozilla.org/MPL/2.0/. */
* file , You can obtain one at https ://mozilla.org/MPL/2.0/. */
use std ::c mp::Ordering ;
use std ::c ell::RefCell ;
use std ::mem ;
use std ::mem ;
use euclid ::default ::Rect ;
use euclid ::default ::Rect ;
use gfx_traits ::print_tree ::PrintTree ;
use log ::warn ;
use script_traits ::compositor ::{ ScrollTreeNodeId , ScrollableNodeInfo } ;
use script_traits ::compositor ::{ ScrollTreeNodeId , ScrollableNodeInfo } ;
use servo_arc ::Arc as ServoArc ;
use servo_arc ::Arc as ServoArc ;
use servo_config ::opts ::DebugOptions ;
use style ::computed_values ::float ::T as ComputedFloat ;
use style ::computed_values ::float ::T as ComputedFloat ;
use style ::computed_values ::mix_blend_mode ::T as ComputedMixBlendMode ;
use style ::computed_values ::mix_blend_mode ::T as ComputedMixBlendMode ;
use style ::computed_values ::overflow_x ::T as ComputedOverflow ;
use style ::computed_values ::overflow_x ::T as ComputedOverflow ;
@ -70,14 +73,18 @@ pub(crate) type ContainingBlockInfo<'a> = ContainingBlockManager<'a, ContainingB
#[ derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd) ]
#[ derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd) ]
pub ( crate ) enum StackingContextSection {
pub ( crate ) enum StackingContextSection {
BackgroundsAndBorders,
Own BackgroundsAndBorders,
Block BackgroundsAndBorders,
Descendant BackgroundsAndBorders,
Content ,
Foreground ,
Outline ,
Outline ,
}
}
impl DisplayList {
impl DisplayList {
pub fn build_stacking_context_tree ( & mut self , fragment_tree : & FragmentTree ) -> StackingContext {
pub fn build_stacking_context_tree (
& mut self ,
fragment_tree : & FragmentTree ,
debug : & DebugOptions ,
) -> StackingContext {
let root_clip_chain_id = self
let root_clip_chain_id = self
. wr
. wr
. define_clip_chain ( None , [ wr ::ClipId ::root ( self . wr . pipeline_id ) ] ) ;
. define_clip_chain ( None , [ wr ::ClipId ::root ( self . wr . pipeline_id ) ] ) ;
@ -105,7 +112,7 @@ impl DisplayList {
for_absolute_and_fixed_descendants : & cb_for_fixed_descendants ,
for_absolute_and_fixed_descendants : & cb_for_fixed_descendants ,
} ;
} ;
let mut root_stacking_context = StackingContext ::create_root ( & self . wr );
let mut root_stacking_context = StackingContext ::create_root ( & self . wr , debug );
for fragment in & fragment_tree . root_fragments {
for fragment in & fragment_tree . root_fragments {
fragment . borrow ( ) . build_stacking_context_tree (
fragment . borrow ( ) . build_stacking_context_tree (
fragment ,
fragment ,
@ -192,37 +199,73 @@ impl DisplayList {
}
}
}
}
pub ( crate ) struct StackingContextFragment {
/// A piece of content that directly belongs to a section of a stacking context.
scroll_node_id : ScrollTreeNodeId ,
///
clip_chain_id : wr ::ClipChainId ,
/// This is generally part of a fragment, like its borders or foreground, but it
section : StackingContextSection ,
/// can also be a stacking container that needs to be painted in fragment order.
containing_block : PhysicalRect < Length > ,
pub ( crate ) enum StackingContextContent {
fragment : ArcRefCell < Fragment > ,
/// A fragment that does not generate a stacking context or stacking container.
Fragment {
scroll_node_id : ScrollTreeNodeId ,
clip_chain_id : wr ::ClipChainId ,
section : StackingContextSection ,
containing_block : PhysicalRect < Length > ,
fragment : ArcRefCell < Fragment > ,
} ,
/// An index into [StackingContext::atomic_inline_stacking_containers].
///
/// There is no section field, because these are always in [StackingContextSection::Foreground].
AtomicInlineStackingContainer { index : usize } ,
}
}
impl StackingContextFragment {
impl StackingContextContent {
fn build_display_list ( & self , builder : & mut DisplayListBuilder ) {
fn section ( & self ) -> StackingContextSection {
builder . current_scroll_node_id = self . scroll_node_id ;
match self {
builder . current_clip_chain_id = self . clip_chain_id ;
Self ::Fragment { section , .. } = > * section ,
self . fragment
Self ::AtomicInlineStackingContainer { .. } = > StackingContextSection ::Foreground ,
. borrow ( )
}
. build_display_list ( builder , & self . containing_block , self . section ) ;
}
fn build_display_list (
& self ,
builder : & mut DisplayListBuilder ,
inline_stacking_containers : & [ StackingContext ] ,
) {
match self {
Self ::Fragment {
scroll_node_id ,
clip_chain_id ,
section ,
containing_block ,
fragment ,
} = > {
builder . current_scroll_node_id = * scroll_node_id ;
builder . current_clip_chain_id = * clip_chain_id ;
fragment
. borrow ( )
. build_display_list ( builder , containing_block , * section ) ;
} ,
Self ::AtomicInlineStackingContainer { index } = > {
inline_stacking_containers [ * index ] . build_display_list ( builder ) ;
} ,
}
}
}
}
}
#[ derive(Clone, Copy, Eq, PartialEq) ]
#[ derive(Clone, Copy, Debug, Eq, PartialEq)]
pub ( crate ) enum StackingContextType {
pub ( crate ) enum StackingContextType {
Real ,
Real StackingContext ,
PseudoPositioned ,
PositionedStackingContainer ,
PseudoFloat ,
FloatStackingContainer ,
PseudoAtomicInline ,
AtomicInlineStackingContainer ,
}
}
/// A [StackingContext] represents either a stacking context or a stacking
/// Either a stacking context or a stacking container, per the definitions in
/// container according to the definitions outlined in
/// <https://drafts.csswg.org/css-position-4/#painting-order>.
/// <https://drafts.csswg.org/css-position-4/#painting-order>
///
/// Stacking containers are sometimes called "pseudo-stacking contexts"
/// We use the term “real stacking context” in situations that call for a
/// in the Servo source.
/// stacking context but not a stacking container .
pub struct StackingContext {
pub struct StackingContext {
/// The spatial id of this fragment. This is used to properly handle
/// The spatial id of this fragment. This is used to properly handle
/// things like preserve-3d.
/// things like preserve-3d.
@ -231,34 +274,61 @@ pub struct StackingContext {
/// The fragment that established this stacking context.
/// The fragment that established this stacking context.
initializing_fragment_style : Option < ServoArc < ComputedValues > > ,
initializing_fragment_style : Option < ServoArc < ComputedValues > > ,
/// The type of this StackingC ontext. Used for collecting and sorting.
/// The type of this stacking c ontext. Used for collecting and sorting.
context_type : StackingContextType ,
context_type : StackingContextType ,
/// Fragments that make up the content of this stacking context .
/// The contents that need to be painted in fragment order .
fragments: Vec < StackingContextFragm ent> ,
contents: Vec < StackingContextCont ent> ,
/// All non-float stacking context and pseudo stacking context children
/// Stacking contexts that need to be stolen by the parent stacking context
/// of this stacking context.
/// if this is a stacking container, that is, real stacking contexts and
stacking_contexts : Vec < StackingContext > ,
/// positioned stacking containers (where ‘ z-index’ is auto).
/// <https://drafts.csswg.org/css-position-4/#paint-a-stacking-container>
/// All float stacking container children of this stacking context.
/// These are stored separately because they should not be passed up to
/// their real stacking context ancestors. From the definition of stacking
/// containers from <https://drafts.csswg.org/css-position-4#painting-order>:
///
/// > To paint a stacking container, given a box root and a canvas canvas:
/// > To paint a stacking container, given a box root and a canvas canvas:
/// > 1. Paint a stacking context given root and canvas, treating root as
/// > 1. Paint a stacking context given root and canvas, treating root as
/// > if it created a new stacking context, but omitting any positioned
/// > if it created a new stacking context, but omitting any positioned
/// > descendants or descendants that actually create a stacking context
/// > descendants or descendants that actually create a stacking context
/// > (letting the parent stacking context paint them, instead).
/// > (letting the parent stacking context paint them, instead).
///
real_stacking_contexts_and_positioned_stacking_containers : Vec < StackingContext > ,
/// Note that all stacking containers / pseudo stacking contexts are passed up
/// to parent stacking contexts, except in the case of floats.
/// Float stacking containers.
float_stacking_contexts : Vec < StackingContext > ,
/// Separate from real_stacking_contexts_or_positioned_stacking_containers
/// because they should never be stolen by the parent stacking context.
/// <https://drafts.csswg.org/css-position-4/#paint-a-stacking-container>
float_stacking_containers : Vec < StackingContext > ,
/// Atomic inline stacking containers.
/// Separate from real_stacking_contexts_or_positioned_stacking_containers
/// because they should never be stolen by the parent stacking context, and
/// separate from float_stacking_containers so that [StackingContextContent]
/// can index into this vec to paint them in fragment order.
/// <https://drafts.csswg.org/css-position-4/#paint-a-stacking-container>
/// <https://drafts.csswg.org/css-position-4/#paint-a-box-in-a-line-box>
atomic_inline_stacking_containers : Vec < StackingContext > ,
/// Information gathered about the painting order, for [Self::debug_print].
debug_print_items : Option < RefCell < Vec < DebugPrintItem > > > ,
}
/// Refers to one of the child contents or stacking contexts of a [StackingContext].
#[ derive(Clone, Copy) ]
pub struct DebugPrintItem {
field : DebugPrintField ,
index : usize ,
}
/// Refers to one of the vecs of a [StackingContext].
#[ derive(Clone, Copy) ]
pub enum DebugPrintField {
Contents ,
RealStackingContextsAndPositionedStackingContainers ,
FloatStackingContainers ,
AtomicInlineStackingContainers ,
}
}
impl StackingContext {
impl StackingContext {
pub ( crate ) fn new (
fn create_descendant (
& self ,
spatial_id : wr ::SpatialId ,
spatial_id : wr ::SpatialId ,
initializing_fragment_style : ServoArc < ComputedValues > ,
initializing_fragment_style : ServoArc < ComputedValues > ,
context_type : StackingContextType ,
context_type : StackingContextType ,
@ -267,30 +337,42 @@ impl StackingContext {
spatial_id ,
spatial_id ,
initializing_fragment_style : Some ( initializing_fragment_style ) ,
initializing_fragment_style : Some ( initializing_fragment_style ) ,
context_type ,
context_type ,
fragments : vec ! [ ] ,
contents : vec ! [ ] ,
stacking_contexts : vec ! [ ] ,
real_stacking_contexts_and_positioned_stacking_containers : vec ! [ ] ,
float_stacking_contexts : vec ! [ ] ,
float_stacking_containers : vec ! [ ] ,
atomic_inline_stacking_containers : vec ! [ ] ,
debug_print_items : self . debug_print_items . is_some ( ) . then ( | | vec! [ ] . into ( ) ) ,
}
}
}
}
pub ( crate ) fn create_root ( wr : & wr ::DisplayListBuilder ) -> Self {
pub ( crate ) fn create_root ( wr : & wr ::DisplayListBuilder , debug : & DebugOptions ) -> Self {
Self {
Self {
spatial_id : wr ::SpaceAndClipInfo ::root_scroll ( wr . pipeline_id ) . spatial_id ,
spatial_id : wr ::SpaceAndClipInfo ::root_scroll ( wr . pipeline_id ) . spatial_id ,
initializing_fragment_style : None ,
initializing_fragment_style : None ,
context_type : StackingContextType ::Real ,
context_type : StackingContextType ::RealStackingContext ,
fragments : vec ! [ ] ,
contents : vec ! [ ] ,
stacking_contexts : vec ! [ ] ,
real_stacking_contexts_and_positioned_stacking_containers : vec ! [ ] ,
float_stacking_contexts : vec ! [ ] ,
float_stacking_containers : vec ! [ ] ,
atomic_inline_stacking_containers : vec ! [ ] ,
debug_print_items : debug . dump_stacking_context_tree . then ( | | vec! [ ] . into ( ) ) ,
}
}
}
}
/// Add a child stacking context to this stacking context.
/// Add a child stacking context to this stacking context.
fn add_stacking_context ( & mut self , stacking_context : StackingContext ) {
fn add_stacking_context ( & mut self , stacking_context : StackingContext ) {
if stacking_context . context_type = = StackingContextType ::PseudoFloat {
match stacking_context . context_type {
self . float_stacking_contexts . push ( stacking_context ) ;
StackingContextType ::RealStackingContext = > {
} else {
& mut self . real_stacking_contexts_and_positioned_stacking_containers
self . stacking_contexts . push ( stacking_context ) ;
} ,
StackingContextType ::PositionedStackingContainer = > {
& mut self . real_stacking_contexts_and_positioned_stacking_containers
} ,
StackingContextType ::FloatStackingContainer = > & mut self . float_stacking_containers ,
StackingContextType ::AtomicInlineStackingContainer = > {
& mut self . atomic_inline_stacking_containers
} ,
}
}
. push ( stacking_context )
}
}
fn z_index ( & self ) -> i32 {
fn z_index ( & self ) -> i32 {
@ -300,24 +382,32 @@ impl StackingContext {
}
}
pub ( crate ) fn sort ( & mut self ) {
pub ( crate ) fn sort ( & mut self ) {
self . fragments . sort_by ( | a , b | a . section . cmp ( & b . section ) ) ;
self . contents . sort_by ( | a , b | a . section ( ) . cmp ( & b . section ( ) ) ) ;
self . real_stacking_contexts_and_positioned_stacking_containers
. sort_by ( | a , b | a . z_index ( ) . cmp ( & b . z_index ( ) ) ) ;
self . stacking_contexts . sort_by ( | a , b | {
debug_assert! ( self
let a_z_index = a . z_index ( ) ;
. real_stacking_contexts_and_positioned_stacking_containers
let b_z_index = b . z_index ( ) ;
. iter ( )
if a_z_index ! = 0 | | b_z_index ! = 0 {
. all ( | c | match c . context_type {
return a_z_index . cmp ( & b_z_index ) ;
StackingContextType ::RealStackingContext |
}
StackingContextType ::PositionedStackingContainer = > true ,
_ = > false ,
match ( a . context_type , b . context_type ) {
} ) ) ;
( StackingContextType ::PseudoFloat , StackingContextType ::PseudoFloat ) = > {
debug_assert! ( self
Ordering ::Equal
. float_stacking_containers
} ,
. iter ( )
( StackingContextType ::PseudoFloat , _ ) = > Ordering ::Less ,
. all (
( _ , StackingContextType ::PseudoFloat ) = > Ordering ::Greater ,
| c | c . context_type = = StackingContextType ::FloatStackingContainer & &
( _ , _ ) = > Ordering ::Equal ,
c . z_index ( ) = = 0
}
) ) ;
} ) ;
debug_assert! ( self
. atomic_inline_stacking_containers
. iter ( )
. all (
| c | c . context_type = = StackingContextType ::AtomicInlineStackingContainer & &
c . z_index ( ) = = 0
) ) ;
}
}
fn push_webrender_stacking_context_if_necessary (
fn push_webrender_stacking_context_if_necessary (
@ -421,20 +511,23 @@ impl StackingContext {
// Let’ s find the corresponding fragment.
// Let’ s find the corresponding fragment.
// The fragment generated by the root element is the first one here, unless…
// The fragment generated by the root element is the first one here, unless…
let first_if_any = self . fragm ents. first ( ) . or_else ( | | {
let first_if_any = self . cont ents. first ( ) . or_else ( | | {
// There wasn’ t any `StackingContextFragment` in the root `StackingContext`,
// There wasn’ t any `StackingContextFragment` in the root `StackingContext`,
// because the root element generates a stacking context. Let’ s find that one.
// because the root element generates a stacking context. Let’ s find that one.
self . stacking_contexts
self . real_ stacking_contexts_and_positioned_stacking_containers
. first ( )
. first ( )
. and_then ( | first_child_stacking_context | {
. and_then ( | first_child_stacking_context | {
first_child_stacking_context . fragm ents. first ( )
first_child_stacking_context . cont ents. first ( )
} )
} )
} ) ;
} ) ;
macro_rules ! debug_panic {
macro_rules ! debug_panic {
( $msg : expr ) = > {
( $msg : expr ) = > {
if cfg! ( debug_assertions ) {
if cfg! ( debug_assertions ) {
panic! ( $msg )
panic! ( $msg ) ;
} else {
warn! ( $msg ) ;
return ;
}
}
} ;
} ;
}
}
@ -444,15 +537,17 @@ impl StackingContext {
} else {
} else {
// This should only happen if the root element has `display: none`
// This should only happen if the root element has `display: none`
debug_panic! ( " `CanvasBackground::for_root_element` should have returned `style: None` " ) ;
debug_panic! ( " `CanvasBackground::for_root_element` should have returned `style: None` " ) ;
return ;
} ;
} ;
let fragment = first_stacking_context_fragment . fragment . borrow ( ) ;
let StackingContextContent ::Fragment { fragment , scroll_node_id , containing_block , .. }
= first_stacking_context_fragment else {
debug_panic! ( " Expected a fragment, not a stacking container " ) ;
} ;
let fragment = fragment . borrow ( ) ;
let box_fragment = match & * fragment {
let box_fragment = match & * fragment {
Fragment ::Box ( box_fragment ) | Fragment ::Float ( box_fragment ) = > box_fragment ,
Fragment ::Box ( box_fragment ) | Fragment ::Float ( box_fragment ) = > box_fragment ,
_ = > {
_ = > {
debug_panic! ( " Expected a box-generated fragment " ) ;
debug_panic! ( " Expected a box-generated fragment " ) ;
return ;
} ,
} ,
} ;
} ;
@ -465,7 +560,7 @@ impl StackingContext {
// The root element may have a CSS transform, and we want the canvas’
// The root element may have a CSS transform, and we want the canvas’
// background image to be transformed. To do so, take its `SpatialId`
// background image to be transformed. To do so, take its `SpatialId`
// (but not its `ClipId`)
// (but not its `ClipId`)
builder . current_scroll_node_id = first_stacking_context_fragment . scroll_node_id ;
builder . current_scroll_node_id = * scroll_node_id ;
// Now we need express the painting area rectangle in the local coordinate system,
// Now we need express the painting area rectangle in the local coordinate system,
// which differs from the top-level coordinate system based on…
// which differs from the top-level coordinate system based on…
@ -487,10 +582,8 @@ impl StackingContext {
}
}
}
}
let mut fragment_builder = super ::BuilderForBoxFragment ::new (
let mut fragment_builder =
box_fragment ,
super ::BuilderForBoxFragment ::new ( box_fragment , containing_block ) ;
& first_stacking_context_fragment . containing_block ,
) ;
let source = super ::background ::Source ::Canvas {
let source = super ::background ::Source ::Canvas {
style ,
style ,
painting_area ,
painting_area ,
@ -501,63 +594,159 @@ impl StackingContext {
pub ( crate ) fn build_display_list ( & self , builder : & mut DisplayListBuilder ) {
pub ( crate ) fn build_display_list ( & self , builder : & mut DisplayListBuilder ) {
let pushed_context = self . push_webrender_stacking_context_if_necessary ( builder ) ;
let pushed_context = self . push_webrender_stacking_context_if_necessary ( builder ) ;
// Properly order display items that make up a stacking context. "Steps" here
// Properly order display items that make up a stacking context.
// refer to the steps in CSS 2.1 Appendix E.
// “Steps” here refer to the steps in CSS 2.1 Appendix E.
// Note that “positioned descendants” is generalised to include all descendants that
// generate stacking contexts (csswg-drafts#2717), except in the phrase “any positioned
// descendants or descendants that actually create a stacking context”, where the term
// means positioned descendants that do not generate stacking contexts.
// Steps 1 and 2: Borders and background for the root
// Steps 1 and 2: Borders and background for the root
let mut child_fragments = self . fragments . iter ( ) . peekable ( ) ;
let mut c ontents = self . cont ents. iter ( ) . enumerate( ) . peekable( ) ;
while child_fragments . peek ( ) . map_or ( false , | child | {
while c ont ents. peek ( ) . map_or ( false , | ( _ , child ) | {
child . section = = StackingContextSection :: BackgroundsAndBorders
child . section ( ) = = StackingContextSection ::Own BackgroundsAndBorders
} ) {
} ) {
child_fragments . next ( ) . unwrap ( ) . build_display_list ( builder ) ;
let ( i , child ) = contents . next ( ) . unwrap ( ) ;
self . debug_push_print_item ( DebugPrintField ::Contents , i ) ;
child . build_display_list ( builder , & self . atomic_inline_stacking_containers ) ;
}
}
// Step 3: Positioned descendants with negative z-indices
// Step 3: Stacking contexts with negative ‘ z-index’
let mut child_stacking_contexts = self . stacking_contexts . iter ( ) . peekable ( ) ;
let mut real_stacking_contexts_and_positioned_stacking_containers = self
while child_stacking_contexts
. real_stacking_contexts_and_positioned_stacking_containers
. iter ( )
. enumerate ( )
. peekable ( ) ;
while real_stacking_contexts_and_positioned_stacking_containers
. peek ( )
. peek ( )
. map_or ( false , | child | child . z_index ( ) < 0 )
. map_or ( false , | ( _ , child ) | child . z_index ( ) < 0 )
{
{
let child_context = child_stacking_contexts . next ( ) . unwrap ( ) ;
let ( i , child ) = real_stacking_contexts_and_positioned_stacking_containers
child_context . build_display_list ( builder ) ;
. next ( )
. unwrap ( ) ;
self . debug_push_print_item (
DebugPrintField ::RealStackingContextsAndPositionedStackingContainers ,
i ,
) ;
child . build_display_list ( builder ) ;
}
}
// Step 4: Block backgrounds and borders
// Step 4: Block backgrounds and borders
while child_fragments . peek ( ) . map_or ( false , | child | {
while c ont ents. peek ( ) . map_or ( false , | ( _ , child ) | {
child . section = = StackingContextSection ::BlockBackgroundsAndBorders
child . section ( ) = = StackingContextSection ::Descendant BackgroundsAndBorders
} ) {
} ) {
child_fragments . next ( ) . unwrap ( ) . build_display_list ( builder ) ;
let ( i , child ) = contents . next ( ) . unwrap ( ) ;
self . debug_push_print_item ( DebugPrintField ::Contents , i ) ;
child . build_display_list ( builder , & self . atomic_inline_stacking_containers ) ;
}
}
// Step 5: Floats
// Step 5: Float stacking containers
for child_context in & self . float_stacking_contexts {
for ( i , child ) in self . float_stacking_containers . iter ( ) . enumerate ( ) {
child_context . build_display_list ( builder ) ;
self . debug_push_print_item ( DebugPrintField ::FloatStackingContainers , i ) ;
child . build_display_list ( builder ) ;
}
}
// Step 6: Content
// Step s 6 and 7: Fragments and inline stacking containers
while c hild_fragm ents. peek ( ) . map_or ( false , | child | {
while c ont ents. peek ( ) . map_or ( false , | ( _ , child ) | {
child . section = = StackingContextSection ::Content
child . section ( ) = = StackingContextSection ::Foreground
} ) {
} ) {
child_fragments . next ( ) . unwrap ( ) . build_display_list ( builder ) ;
let ( i , child ) = contents . next ( ) . unwrap ( ) ;
self . debug_push_print_item ( DebugPrintField ::Contents , i ) ;
child . build_display_list ( builder , & self . atomic_inline_stacking_containers ) ;
}
}
// Step 7, 8 & 9: Inlines that generate stacking contexts and positioned
// Steps 8 and 9: Stacking contexts with non-negative ‘ z-index’ , and
// descendants with nonnegative, numeric z-indices
// positioned stacking containers (where ‘ z-index’ is auto)
for child_context in child_stacking_contexts {
for ( i , child ) in real_stacking_contexts_and_positioned_stacking_containers {
child_context . build_display_list ( builder ) ;
self . debug_push_print_item (
DebugPrintField ::RealStackingContextsAndPositionedStackingContainers ,
i ,
) ;
child . build_display_list ( builder ) ;
}
}
// Step 10: Outline
// Step 10: Outline
while child_fragments . peek ( ) . map_or ( false , | child | {
while c ont ents. peek ( ) . map_or ( false , | ( _ , child ) | {
child . section = = StackingContextSection ::Outline
child . section ( ) = = StackingContextSection ::Outline
} ) {
} ) {
child_fragments . next ( ) . unwrap ( ) . build_display_list ( builder ) ;
let ( i , child ) = contents . next ( ) . unwrap ( ) ;
self . debug_push_print_item ( DebugPrintField ::Contents , i ) ;
child . build_display_list ( builder , & self . atomic_inline_stacking_containers ) ;
}
}
if pushed_context {
if pushed_context {
builder . display_list . wr . pop_stacking_context ( ) ;
builder . display_list . wr . pop_stacking_context ( ) ;
}
}
}
}
/// Store the fact that something was painted, if [Self::debug_print_items] is not None.
///
/// This is used to help reconstruct the original painting order in [Self::debug_print] without
/// duplicating our painting order logic, since that could fall out of sync with the real logic.
fn debug_push_print_item ( & self , field : DebugPrintField , index : usize ) {
if let Some ( items ) = self . debug_print_items . as_ref ( ) {
items . borrow_mut ( ) . push ( DebugPrintItem { field , index } ) ;
}
}
/// Print the stacking context tree.
pub fn debug_print ( & self ) {
if self . debug_print_items . is_none ( ) {
warn! ( " failed to print stacking context tree: debug_print_items was None " ) ;
return ;
}
let mut tree = PrintTree ::new ( " Stacking context tree " . to_owned ( ) ) ;
self . debug_print_with_tree ( & mut tree ) ;
}
/// Print a subtree with the given [PrintTree], or panic if [Self::debug_print_items] is None.
fn debug_print_with_tree ( & self , tree : & mut PrintTree ) {
match self . context_type {
StackingContextType ::RealStackingContext = > {
tree . new_level ( format! ( " {:?} z= {} " , self . context_type , self . z_index ( ) ) ) ;
} ,
StackingContextType ::AtomicInlineStackingContainer = > {
// do nothing; we print the heading with its index in DebugPrintField::Contents
} ,
_ = > {
tree . new_level ( format! ( " {:?} " , self . context_type ) ) ;
} ,
}
for DebugPrintItem { field , index } in
self . debug_print_items . as_ref ( ) . unwrap ( ) . borrow ( ) . iter ( )
{
match field {
DebugPrintField ::Contents = > match self . contents [ * index ] {
StackingContextContent ::Fragment { section , .. } = > {
tree . add_item ( format! ( " {:?} " , section ) ) ;
} ,
StackingContextContent ::AtomicInlineStackingContainer { index } = > {
tree . new_level ( format! ( " AtomicInlineStackingContainer # {} " , index ) ) ;
self . atomic_inline_stacking_containers [ index ] . debug_print_with_tree ( tree ) ;
tree . end_level ( ) ;
} ,
} ,
DebugPrintField ::RealStackingContextsAndPositionedStackingContainers = > {
self . real_stacking_contexts_and_positioned_stacking_containers [ * index ]
. debug_print_with_tree ( tree ) ;
} ,
DebugPrintField ::FloatStackingContainers = > {
self . float_stacking_containers [ * index ] . debug_print_with_tree ( tree ) ;
} ,
DebugPrintField ::AtomicInlineStackingContainers = > {
// do nothing; we print these in DebugPrintField::Contents
} ,
}
}
match self . context_type {
StackingContextType ::AtomicInlineStackingContainer = > {
// do nothing; we print the heading with its index in DebugPrintField::Contents
} ,
_ = > {
tree . end_level ( ) ;
} ,
}
}
}
}
#[ derive(PartialEq) ]
#[ derive(PartialEq) ]
@ -624,13 +813,15 @@ impl Fragment {
) ;
) ;
} ,
} ,
Fragment ::Text ( _ ) | Fragment ::Image ( _ ) | Fragment ::IFrame ( _ ) = > {
Fragment ::Text ( _ ) | Fragment ::Image ( _ ) | Fragment ::IFrame ( _ ) = > {
stacking_context . fragments . push ( StackingContextFragment {
stacking_context
section : StackingContextSection ::Content ,
. contents
scroll_node_id : containing_block . scroll_node_id ,
. push ( StackingContextContent ::Fragment {
clip_chain_id : containing_block . clip_chain_id ,
section : StackingContextSection ::Foreground ,
containing_block : containing_block . rect ,
scroll_node_id : containing_block . scroll_node_id ,
fragment : fragment_ref . clone ( ) ,
clip_chain_id : containing_block . clip_chain_id ,
} ) ;
containing_block : containing_block . rect ,
fragment : fragment_ref . clone ( ) ,
} ) ;
} ,
} ,
}
}
}
}
@ -645,20 +836,20 @@ struct ReferenceFrameData {
impl BoxFragment {
impl BoxFragment {
fn get_stacking_context_type ( & self ) -> Option < StackingContextType > {
fn get_stacking_context_type ( & self ) -> Option < StackingContextType > {
if self . style . establishes_stacking_context ( ) {
if self . style . establishes_stacking_context ( ) {
return Some ( StackingContextType ::Real ) ;
return Some ( StackingContextType ::Real StackingContext ) ;
}
}
let box_style = & self . style . get_box ( ) ;
let box_style = & self . style . get_box ( ) ;
if box_style . position ! = ComputedPosition ::Static {
if box_style . position ! = ComputedPosition ::Static {
return Some ( StackingContextType ::Pseudo Positioned) ;
return Some ( StackingContextType :: PositionedStackingContainer ) ;
}
}
if box_style . float ! = ComputedFloat ::None {
if box_style . float ! = ComputedFloat ::None {
return Some ( StackingContextType ::PseudoFloat ) ;
return Some ( StackingContextType ::FloatStackingContainer ) ;
}
}
if box_style . display . is_atomic_inline_level ( ) {
if box_style . display . is_atomic_inline_level ( ) {
return Some ( StackingContextType ::Pseudo AtomicInline) ;
return Some ( StackingContextType :: AtomicInlineStackingContainer ) ;
}
}
None
None
@ -666,14 +857,14 @@ impl BoxFragment {
fn get_stacking_context_section ( & self ) -> StackingContextSection {
fn get_stacking_context_section ( & self ) -> StackingContextSection {
if self . get_stacking_context_type ( ) . is_some ( ) {
if self . get_stacking_context_type ( ) . is_some ( ) {
return StackingContextSection :: BackgroundsAndBorders;
return StackingContextSection ::Own BackgroundsAndBorders;
}
}
if self . style . get_box ( ) . display . outside ( ) = = DisplayOutside ::Inline {
if self . style . get_box ( ) . display . outside ( ) = = DisplayOutside ::Inline {
return StackingContextSection ::Content ;
return StackingContextSection ::Foreground ;
}
}
StackingContextSection ::Block BackgroundsAndBorders
StackingContextSection ::Descendant BackgroundsAndBorders
}
}
fn build_stacking_context_tree (
fn build_stacking_context_tree (
@ -778,7 +969,18 @@ impl BoxFragment {
} ,
} ,
} ;
} ;
let mut child_stacking_context = StackingContext ::new (
if context_type = = StackingContextType ::AtomicInlineStackingContainer {
// Push a dummy fragment that indicates when the new stacking context should be painted.
parent_stacking_context . contents . push (
StackingContextContent ::AtomicInlineStackingContainer {
index : parent_stacking_context
. atomic_inline_stacking_containers
. len ( ) ,
} ,
) ;
}
let mut child_stacking_context = parent_stacking_context . create_descendant (
containing_block . scroll_node_id . spatial_id ,
containing_block . scroll_node_id . spatial_id ,
self . style . clone ( ) ,
self . style . clone ( ) ,
context_type ,
context_type ,
@ -792,9 +994,10 @@ impl BoxFragment {
) ;
) ;
let mut stolen_children = vec! [ ] ;
let mut stolen_children = vec! [ ] ;
if context_type ! = StackingContextType ::Real {
if context_type ! = StackingContextType ::Real StackingContext {
stolen_children = mem ::replace (
stolen_children = mem ::replace (
& mut child_stacking_context . stacking_contexts ,
& mut child_stacking_context
. real_stacking_contexts_and_positioned_stacking_containers ,
stolen_children ,
stolen_children ,
) ;
) ;
}
}
@ -802,7 +1005,7 @@ impl BoxFragment {
child_stacking_context . sort ( ) ;
child_stacking_context . sort ( ) ;
parent_stacking_context . add_stacking_context ( child_stacking_context ) ;
parent_stacking_context . add_stacking_context ( child_stacking_context ) ;
parent_stacking_context
parent_stacking_context
. stacking_contexts
. real_ stacking_contexts_and_positioned_stacking_containers
. append ( & mut stolen_children ) ;
. append ( & mut stolen_children ) ;
}
}
@ -825,21 +1028,25 @@ impl BoxFragment {
new_clip_chain_id = clip_chain_id ;
new_clip_chain_id = clip_chain_id ;
}
}
stacking_context . fragments . push ( StackingContextFragment {
stacking_context
scroll_node_id : new_scroll_node_id ,
. contents
clip_chain_id : new_clip_chain_id ,
. push ( StackingContextContent ::Fragment {
section : self . get_stacking_context_section ( ) ,
containing_block : containing_block . rect ,
fragment : fragment . clone ( ) ,
} ) ;
if self . style . get_outline ( ) . outline_width . px ( ) > 0.0 {
stacking_context . fragments . push ( StackingContextFragment {
scroll_node_id : new_scroll_node_id ,
scroll_node_id : new_scroll_node_id ,
clip_chain_id : new_clip_chain_id ,
clip_chain_id : new_clip_chain_id ,
section : StackingContextSection::Outline ,
section : self . get_stacking_context_section ( ) ,
containing_block : containing_block . rect ,
containing_block : containing_block . rect ,
fragment : fragment . clone ( ) ,
fragment : fragment . clone ( ) ,
} ) ;
} ) ;
if self . style . get_outline ( ) . outline_width . px ( ) > 0.0 {
stacking_context
. contents
. push ( StackingContextContent ::Fragment {
scroll_node_id : new_scroll_node_id ,
clip_chain_id : new_clip_chain_id ,
section : StackingContextSection ::Outline ,
containing_block : containing_block . rect ,
fragment : fragment . clone ( ) ,
} ) ;
}
}
// We want to build the scroll frame after the background and border, because
// We want to build the scroll frame after the background and border, because