Fix painting order of atomic inline stacking containers (#30458)

* Sort stacking contexts and stacking containers by painting order

* fix stealing of stacking containers; fix interleaving with fragments

* actually positioned stacking containers should be stolen too

* update expectations and clean up panic changes

* rework naming and docs

* rename s_c_a_p_s_c to real_s_c_a_p_s_c; fix docs

* rename InlineStackingContainer to AtomicInlineStackingContainer

* rework debug logging to use PrintTree

* clean up docs and PrintTree output

* don't panic unless cfg!(debug_assertions) is true

* update expectations
This commit is contained in:
Delan Azabani 2023-10-07 00:00:00 +08:00 committed by GitHub
parent c06ec90151
commit afe4faa09a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 374 additions and 156 deletions

1
Cargo.lock generated
View file

@ -3094,6 +3094,7 @@ dependencies = [
"serde",
"serde_json",
"servo_arc",
"servo_config",
"servo_url",
"style",
"style_traits",

View file

@ -176,9 +176,12 @@ pub struct DebugOptions {
/// Dumps the rule tree.
pub dump_rule_tree: bool,
/// Print the flow tree after each layout.
/// Print the flow tree (Layout 2013) or fragment tree (Layout 2020) after each layout.
pub dump_flow_tree: bool,
/// Print the stacking context tree after each layout.
pub dump_stacking_context_tree: bool,
/// Print the display list after each layout.
pub dump_display_list: bool,
@ -247,6 +250,7 @@ impl DebugOptions {
"disable-text-aa" => self.disable_text_antialiasing = true,
"dump-display-list" => self.dump_display_list = true,
"dump-display-list-json" => self.dump_display_list_json = true,
"dump-stacking-context-tree" => self.dump_stacking_context_tree = true,
"dump-flow-tree" => self.dump_flow_tree = true,
"dump-rule-tree" => self.dump_rule_tree = true,
"dump-style-tree" => self.dump_style_tree = true,
@ -305,6 +309,10 @@ impl DebugOptions {
"Disable subpixel text antialiasing overriding preference.",
);
print_option("disable-text-aa", "Disable antialiasing of rendered text.");
print_option(
"dump-stacking-context-tree",
"Print the stacking context tree after each layout.",
);
print_option(
"dump-display-list",
"Print the display list after each layout.",
@ -313,7 +321,10 @@ impl DebugOptions {
"dump-display-list-json",
"Print the display list in JSON form.",
);
print_option("dump-flow-tree", "Print the flow tree after each layout.");
print_option(
"dump-flow-tree",
"Print the flow tree (Layout 2013) or fragment tree (Layout 2020) after each layout.",
);
print_option(
"dump-rule-tree",
"Print the style rule tree after each layout.",

View file

@ -84,6 +84,6 @@ impl PrintTree {
impl Drop for PrintTree {
fn drop(&mut self) {
self.flush_queued_item("\u{9492}\u{9472}");
self.flush_queued_item("\u{2514}\u{2500}");
}
}

View file

@ -38,6 +38,7 @@ script_traits = { path = "../script_traits" }
serde = { workspace = true }
serde_json = { workspace = true }
servo_arc = { path = "../servo_arc" }
servo_config = { path = "../config" }
servo_url = { path = "../url" }
style = { path = "../style", features = ["servo"] }
style_traits = { path = "../style_traits" }

View file

@ -2,12 +2,15 @@
* 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/. */
use std::cmp::Ordering;
use std::cell::RefCell;
use std::mem;
use euclid::default::Rect;
use gfx_traits::print_tree::PrintTree;
use log::warn;
use script_traits::compositor::{ScrollTreeNodeId, ScrollableNodeInfo};
use servo_arc::Arc as ServoArc;
use servo_config::opts::DebugOptions;
use style::computed_values::float::T as ComputedFloat;
use style::computed_values::mix_blend_mode::T as ComputedMixBlendMode;
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)]
pub(crate) enum StackingContextSection {
BackgroundsAndBorders,
BlockBackgroundsAndBorders,
Content,
OwnBackgroundsAndBorders,
DescendantBackgroundsAndBorders,
Foreground,
Outline,
}
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
.wr
.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,
};
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 {
fragment.borrow().build_stacking_context_tree(
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.
///
/// This is generally part of a fragment, like its borders or foreground, but it
/// can also be a stacking container that needs to be painted in fragment order.
pub(crate) enum StackingContextContent {
/// 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 {
fn build_display_list(&self, builder: &mut DisplayListBuilder) {
builder.current_scroll_node_id = self.scroll_node_id;
builder.current_clip_chain_id = self.clip_chain_id;
self.fragment
impl StackingContextContent {
fn section(&self) -> StackingContextSection {
match self {
Self::Fragment { section, .. } => *section,
Self::AtomicInlineStackingContainer { .. } => StackingContextSection::Foreground,
}
}
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, &self.containing_block, self.section);
.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 {
Real,
PseudoPositioned,
PseudoFloat,
PseudoAtomicInline,
RealStackingContext,
PositionedStackingContainer,
FloatStackingContainer,
AtomicInlineStackingContainer,
}
/// A [StackingContext] represents either a stacking context or a stacking
/// container according to the definitions outlined in
/// <https://drafts.csswg.org/css-position-4/#painting-order>
/// Stacking containers are sometimes called "pseudo-stacking contexts"
/// in the Servo source.
/// Either a stacking context or a stacking container, per the definitions in
/// <https://drafts.csswg.org/css-position-4/#painting-order>.
///
/// We use the term “real stacking context” in situations that call for a
/// stacking context but not a stacking container.
pub struct StackingContext {
/// The spatial id of this fragment. This is used to properly handle
/// things like preserve-3d.
@ -231,34 +274,61 @@ pub struct StackingContext {
/// The fragment that established this stacking context.
initializing_fragment_style: Option<ServoArc<ComputedValues>>,
/// The type of this StackingContext. Used for collecting and sorting.
/// The type of this stacking context. Used for collecting and sorting.
context_type: StackingContextType,
/// Fragments that make up the content of this stacking context.
fragments: Vec<StackingContextFragment>,
/// The contents that need to be painted in fragment order.
contents: Vec<StackingContextContent>,
/// All non-float stacking context and pseudo stacking context children
/// of this stacking context.
stacking_contexts: Vec<StackingContext>,
/// 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>:
///
/// Stacking contexts that need to be stolen by the parent stacking context
/// if this is a stacking container, that is, real stacking contexts and
/// positioned stacking containers (where z-index is auto).
/// <https://drafts.csswg.org/css-position-4/#paint-a-stacking-container>
/// > 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
/// > if it created a new stacking context, but omitting any positioned
/// > descendants or descendants that actually create a stacking context
/// > (letting the parent stacking context paint them, instead).
///
/// Note that all stacking containers / pseudo stacking contexts are passed up
/// to parent stacking contexts, except in the case of floats.
float_stacking_contexts: Vec<StackingContext>,
real_stacking_contexts_and_positioned_stacking_containers: Vec<StackingContext>,
/// Float stacking containers.
/// 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 {
pub(crate) fn new(
fn create_descendant(
&self,
spatial_id: wr::SpatialId,
initializing_fragment_style: ServoArc<ComputedValues>,
context_type: StackingContextType,
@ -267,30 +337,42 @@ impl StackingContext {
spatial_id,
initializing_fragment_style: Some(initializing_fragment_style),
context_type,
fragments: vec![],
stacking_contexts: vec![],
float_stacking_contexts: vec![],
contents: vec![],
real_stacking_contexts_and_positioned_stacking_containers: 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 {
spatial_id: wr::SpaceAndClipInfo::root_scroll(wr.pipeline_id).spatial_id,
initializing_fragment_style: None,
context_type: StackingContextType::Real,
fragments: vec![],
stacking_contexts: vec![],
float_stacking_contexts: vec![],
context_type: StackingContextType::RealStackingContext,
contents: vec![],
real_stacking_contexts_and_positioned_stacking_containers: 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.
fn add_stacking_context(&mut self, stacking_context: StackingContext) {
if stacking_context.context_type == StackingContextType::PseudoFloat {
self.float_stacking_contexts.push(stacking_context);
} else {
self.stacking_contexts.push(stacking_context);
match stacking_context.context_type {
StackingContextType::RealStackingContext => {
&mut self.real_stacking_contexts_and_positioned_stacking_containers
},
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 {
@ -300,24 +382,32 @@ impl StackingContext {
}
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| {
let a_z_index = a.z_index();
let b_z_index = b.z_index();
if a_z_index != 0 || b_z_index != 0 {
return a_z_index.cmp(&b_z_index);
}
match (a.context_type, b.context_type) {
(StackingContextType::PseudoFloat, StackingContextType::PseudoFloat) => {
Ordering::Equal
},
(StackingContextType::PseudoFloat, _) => Ordering::Less,
(_, StackingContextType::PseudoFloat) => Ordering::Greater,
(_, _) => Ordering::Equal,
}
});
debug_assert!(self
.real_stacking_contexts_and_positioned_stacking_containers
.iter()
.all(|c| match c.context_type {
StackingContextType::RealStackingContext |
StackingContextType::PositionedStackingContainer => true,
_ => false,
}));
debug_assert!(self
.float_stacking_containers
.iter()
.all(
|c| c.context_type == StackingContextType::FloatStackingContainer &&
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(
@ -421,20 +511,23 @@ impl StackingContext {
// Lets find the corresponding fragment.
// The fragment generated by the root element is the first one here, unless…
let first_if_any = self.fragments.first().or_else(|| {
let first_if_any = self.contents.first().or_else(|| {
// There wasnt any `StackingContextFragment` in the root `StackingContext`,
// because the root element generates a stacking context. Lets find that one.
self.stacking_contexts
self.real_stacking_contexts_and_positioned_stacking_containers
.first()
.and_then(|first_child_stacking_context| {
first_child_stacking_context.fragments.first()
first_child_stacking_context.contents.first()
})
});
macro_rules! debug_panic {
($msg: expr) => {
if cfg!(debug_assertions) {
panic!($msg)
panic!($msg);
} else {
warn!($msg);
return;
}
};
}
@ -444,15 +537,17 @@ impl StackingContext {
} else {
// This should only happen if the root element has `display: 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 {
Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => box_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
// background image to be transformed. To do so, take its `SpatialId`
// (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,
// which differs from the top-level coordinate system based on…
@ -487,10 +582,8 @@ impl StackingContext {
}
}
let mut fragment_builder = super::BuilderForBoxFragment::new(
box_fragment,
&first_stacking_context_fragment.containing_block,
);
let mut fragment_builder =
super::BuilderForBoxFragment::new(box_fragment, containing_block);
let source = super::background::Source::Canvas {
style,
painting_area,
@ -501,63 +594,159 @@ impl StackingContext {
pub(crate) fn build_display_list(&self, builder: &mut DisplayListBuilder) {
let pushed_context = self.push_webrender_stacking_context_if_necessary(builder);
// Properly order display items that make up a stacking context. "Steps" here
// refer to the steps in CSS 2.1 Appendix E.
// Properly order display items that make up a stacking context.
// “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
let mut child_fragments = self.fragments.iter().peekable();
while child_fragments.peek().map_or(false, |child| {
child.section == StackingContextSection::BackgroundsAndBorders
let mut contents = self.contents.iter().enumerate().peekable();
while contents.peek().map_or(false, |(_, child)| {
child.section() == StackingContextSection::OwnBackgroundsAndBorders
}) {
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
let mut child_stacking_contexts = self.stacking_contexts.iter().peekable();
while child_stacking_contexts
// Step 3: Stacking contexts with negative z-index
let mut real_stacking_contexts_and_positioned_stacking_containers = self
.real_stacking_contexts_and_positioned_stacking_containers
.iter()
.enumerate()
.peekable();
while real_stacking_contexts_and_positioned_stacking_containers
.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();
child_context.build_display_list(builder);
let (i, child) = real_stacking_contexts_and_positioned_stacking_containers
.next()
.unwrap();
self.debug_push_print_item(
DebugPrintField::RealStackingContextsAndPositionedStackingContainers,
i,
);
child.build_display_list(builder);
}
// Step 4: Block backgrounds and borders
while child_fragments.peek().map_or(false, |child| {
child.section == StackingContextSection::BlockBackgroundsAndBorders
while contents.peek().map_or(false, |(_, child)| {
child.section() == StackingContextSection::DescendantBackgroundsAndBorders
}) {
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
for child_context in &self.float_stacking_contexts {
child_context.build_display_list(builder);
// Step 5: Float stacking containers
for (i, child) in self.float_stacking_containers.iter().enumerate() {
self.debug_push_print_item(DebugPrintField::FloatStackingContainers, i);
child.build_display_list(builder);
}
// Step 6: Content
while child_fragments.peek().map_or(false, |child| {
child.section == StackingContextSection::Content
// Steps 6 and 7: Fragments and inline stacking containers
while contents.peek().map_or(false, |(_, child)| {
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
// descendants with nonnegative, numeric z-indices
for child_context in child_stacking_contexts {
child_context.build_display_list(builder);
// Steps 8 and 9: Stacking contexts with non-negative z-index, and
// positioned stacking containers (where z-index is auto)
for (i, child) in real_stacking_contexts_and_positioned_stacking_containers {
self.debug_push_print_item(
DebugPrintField::RealStackingContextsAndPositionedStackingContainers,
i,
);
child.build_display_list(builder);
}
// Step 10: Outline
while child_fragments.peek().map_or(false, |child| {
child.section == StackingContextSection::Outline
while contents.peek().map_or(false, |(_, child)| {
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 {
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)]
@ -624,8 +813,10 @@ impl Fragment {
);
},
Fragment::Text(_) | Fragment::Image(_) | Fragment::IFrame(_) => {
stacking_context.fragments.push(StackingContextFragment {
section: StackingContextSection::Content,
stacking_context
.contents
.push(StackingContextContent::Fragment {
section: StackingContextSection::Foreground,
scroll_node_id: containing_block.scroll_node_id,
clip_chain_id: containing_block.clip_chain_id,
containing_block: containing_block.rect,
@ -645,20 +836,20 @@ struct ReferenceFrameData {
impl BoxFragment {
fn get_stacking_context_type(&self) -> Option<StackingContextType> {
if self.style.establishes_stacking_context() {
return Some(StackingContextType::Real);
return Some(StackingContextType::RealStackingContext);
}
let box_style = &self.style.get_box();
if box_style.position != ComputedPosition::Static {
return Some(StackingContextType::PseudoPositioned);
return Some(StackingContextType::PositionedStackingContainer);
}
if box_style.float != ComputedFloat::None {
return Some(StackingContextType::PseudoFloat);
return Some(StackingContextType::FloatStackingContainer);
}
if box_style.display.is_atomic_inline_level() {
return Some(StackingContextType::PseudoAtomicInline);
return Some(StackingContextType::AtomicInlineStackingContainer);
}
None
@ -666,14 +857,14 @@ impl BoxFragment {
fn get_stacking_context_section(&self) -> StackingContextSection {
if self.get_stacking_context_type().is_some() {
return StackingContextSection::BackgroundsAndBorders;
return StackingContextSection::OwnBackgroundsAndBorders;
}
if self.style.get_box().display.outside() == DisplayOutside::Inline {
return StackingContextSection::Content;
return StackingContextSection::Foreground;
}
StackingContextSection::BlockBackgroundsAndBorders
StackingContextSection::DescendantBackgroundsAndBorders
}
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,
self.style.clone(),
context_type,
@ -792,9 +994,10 @@ impl BoxFragment {
);
let mut stolen_children = vec![];
if context_type != StackingContextType::Real {
if context_type != StackingContextType::RealStackingContext {
stolen_children = mem::replace(
&mut child_stacking_context.stacking_contexts,
&mut child_stacking_context
.real_stacking_contexts_and_positioned_stacking_containers,
stolen_children,
);
}
@ -802,7 +1005,7 @@ impl BoxFragment {
child_stacking_context.sort();
parent_stacking_context.add_stacking_context(child_stacking_context);
parent_stacking_context
.stacking_contexts
.real_stacking_contexts_and_positioned_stacking_containers
.append(&mut stolen_children);
}
@ -825,7 +1028,9 @@ impl BoxFragment {
new_clip_chain_id = clip_chain_id;
}
stacking_context.fragments.push(StackingContextFragment {
stacking_context
.contents
.push(StackingContextContent::Fragment {
scroll_node_id: new_scroll_node_id,
clip_chain_id: new_clip_chain_id,
section: self.get_stacking_context_section(),
@ -833,7 +1038,9 @@ impl BoxFragment {
fragment: fragment.clone(),
});
if self.style.get_outline().outline_width.px() > 0.0 {
stacking_context.fragments.push(StackingContextFragment {
stacking_context
.contents
.push(StackingContextContent::Fragment {
scroll_node_id: new_scroll_node_id,
clip_chain_id: new_clip_chain_id,
section: StackingContextSection::Outline,

View file

@ -1259,7 +1259,8 @@ impl LayoutThread {
// Build the root stacking context. This turns the `FragmentTree` into a
// tree of fragments in CSS painting order and also creates all
// applicable spatial and clip nodes.
let root_stacking_context = display_list.build_stacking_context_tree(&fragment_tree);
let root_stacking_context =
display_list.build_stacking_context_tree(&fragment_tree, &self.debug);
// Build the rest of the display list which inclues all of the WebRender primitives.
let (iframe_sizes, is_contentful) =
@ -1268,6 +1269,9 @@ impl LayoutThread {
if self.debug.dump_flow_tree {
fragment_tree.print();
}
if self.debug.dump_stacking_context_tree {
root_stacking_context.debug_print();
}
debug!("Layout done!");
// Observe notifications about rendered frames if needed right before

View file

@ -1,2 +0,0 @@
[overflow-scroll-float-paint-order.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[inline-block-zorder-003.xht]
expected: FAIL

View file

@ -1,2 +0,0 @@
[inline-table-zorder-003.xht]
expected: FAIL

View file

@ -0,0 +1,2 @@
[preserve3d-and-flattening-z-order-005.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[select-multiple-covered-by-abspos.html]
expected: FAIL