mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Split stacking context fragments into sections in layout_2020
This allows rendering stacking context content in the proper order. We also need to add a new pseudo stacking context for atomic inlines in order to preserve proper rendering order in some cases.
This commit is contained in:
parent
13ff7ce621
commit
9517190a60
4 changed files with 80 additions and 33 deletions
|
@ -14,20 +14,38 @@ use style::computed_values::overflow_x::T as ComputedOverflow;
|
||||||
use style::computed_values::position::T as ComputedPosition;
|
use style::computed_values::position::T as ComputedPosition;
|
||||||
use style::computed_values::transform_style::T as ComputedTransformStyle;
|
use style::computed_values::transform_style::T as ComputedTransformStyle;
|
||||||
use style::values::computed::Length;
|
use style::values::computed::Length;
|
||||||
|
use style::values::specified::box_::DisplayOutside;
|
||||||
use webrender_api::units::LayoutVector2D;
|
use webrender_api::units::LayoutVector2D;
|
||||||
use webrender_api::{ExternalScrollId, ScrollSensitivity, SpaceAndClipInfo, SpatialId};
|
use webrender_api::{ExternalScrollId, ScrollSensitivity, SpaceAndClipInfo, SpatialId};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
|
pub(crate) enum StackingContextSection {
|
||||||
|
BackgroundsAndBorders,
|
||||||
|
BlockBackgroundsAndBorders,
|
||||||
|
Content,
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct StackingContextFragment<'a> {
|
pub(crate) struct StackingContextFragment<'a> {
|
||||||
space_and_clip: SpaceAndClipInfo,
|
space_and_clip: SpaceAndClipInfo,
|
||||||
|
section: StackingContextSection,
|
||||||
containing_block: PhysicalRect<Length>,
|
containing_block: PhysicalRect<Length>,
|
||||||
fragment: &'a Fragment,
|
fragment: &'a Fragment,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> StackingContextFragment<'a> {
|
||||||
|
fn build_display_list(&self, builder: &mut DisplayListBuilder) {
|
||||||
|
builder.current_space_and_clip = self.space_and_clip;
|
||||||
|
self.fragment
|
||||||
|
.build_display_list(builder, &self.containing_block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
pub(crate) enum StackingContextType {
|
pub(crate) enum StackingContextType {
|
||||||
Real,
|
Real,
|
||||||
PseudoPositioned,
|
PseudoPositioned,
|
||||||
PseudoFloat,
|
PseudoFloat,
|
||||||
|
PseudoAtomicInline,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct StackingContext<'a> {
|
pub(crate) struct StackingContext<'a> {
|
||||||
|
@ -59,7 +77,9 @@ impl<'a> StackingContext<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn sort_stacking_contexts(&mut self) {
|
pub(crate) fn sort(&mut self) {
|
||||||
|
self.fragments.sort_by(|a, b| a.section.cmp(&b.section));
|
||||||
|
|
||||||
self.stacking_contexts.sort_by(|a, b| {
|
self.stacking_contexts.sort_by(|a, b| {
|
||||||
if a.z_index != 0 || b.z_index != 0 {
|
if a.z_index != 0 || b.z_index != 0 {
|
||||||
return a.z_index.cmp(&b.z_index);
|
return a.z_index.cmp(&b.z_index);
|
||||||
|
@ -79,12 +99,16 @@ impl<'a> StackingContext<'a> {
|
||||||
pub(crate) fn build_display_list(&'a self, builder: &'a mut DisplayListBuilder) {
|
pub(crate) fn build_display_list(&'a self, builder: &'a mut DisplayListBuilder) {
|
||||||
// Properly order display items that make up a stacking context. "Steps" here
|
// Properly order display items that make up a stacking context. "Steps" here
|
||||||
// refer to the steps in CSS 2.1 Appendix E.
|
// refer to the steps in CSS 2.1 Appendix E.
|
||||||
//
|
|
||||||
// TODO(mrobinson): The fragment content of the stacking context needs to be
|
|
||||||
// organized or sorted into the different sections according to the appropriate
|
|
||||||
// paint order.
|
|
||||||
|
|
||||||
// Step 3: Positioned descendants with negative z-indices.
|
// 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
|
||||||
|
}) {
|
||||||
|
child_fragments.next().unwrap().build_display_list(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Positioned descendants with negative z-indices
|
||||||
let mut child_stacking_contexts = self.stacking_contexts.iter().peekable();
|
let mut child_stacking_contexts = self.stacking_contexts.iter().peekable();
|
||||||
while child_stacking_contexts
|
while child_stacking_contexts
|
||||||
.peek()
|
.peek()
|
||||||
|
@ -94,21 +118,27 @@ impl<'a> StackingContext<'a> {
|
||||||
child_context.build_display_list(builder);
|
child_context.build_display_list(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4: Block backgrounds and borders.
|
// Step 4: Block backgrounds and borders
|
||||||
for child in &self.fragments {
|
while child_fragments.peek().map_or(false, |child| {
|
||||||
builder.current_space_and_clip = child.space_and_clip;
|
child.section == StackingContextSection::BlockBackgroundsAndBorders
|
||||||
child
|
}) {
|
||||||
.fragment
|
child_fragments.next().unwrap().build_display_list(builder);
|
||||||
.build_display_list(builder, &child.containing_block);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 5: Floats.
|
// Step 5: Floats
|
||||||
for child_context in &self.float_stacking_contexts {
|
for child_context in &self.float_stacking_contexts {
|
||||||
child_context.build_display_list(builder);
|
child_context.build_display_list(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Step 6: Content
|
||||||
|
while child_fragments.peek().map_or(false, |child| {
|
||||||
|
child.section == StackingContextSection::Content
|
||||||
|
}) {
|
||||||
|
child_fragments.next().unwrap().build_display_list(builder);
|
||||||
|
}
|
||||||
|
|
||||||
// Step 7, 8 & 9: Inlines that generate stacking contexts and positioned
|
// Step 7, 8 & 9: Inlines that generate stacking contexts and positioned
|
||||||
// descendants with nonnegative, numeric z-indices.
|
// descendants with nonnegative, numeric z-indices
|
||||||
for child_context in child_stacking_contexts {
|
for child_context in child_stacking_contexts {
|
||||||
child_context.build_display_list(builder);
|
child_context.build_display_list(builder);
|
||||||
}
|
}
|
||||||
|
@ -134,6 +164,7 @@ impl Fragment {
|
||||||
},
|
},
|
||||||
Fragment::Text(_) | Fragment::Image(_) => {
|
Fragment::Text(_) | Fragment::Image(_) => {
|
||||||
stacking_context.fragments.push(StackingContextFragment {
|
stacking_context.fragments.push(StackingContextFragment {
|
||||||
|
section: StackingContextSection::Content,
|
||||||
space_and_clip: builder.current_space_and_clip,
|
space_and_clip: builder.current_space_and_clip,
|
||||||
containing_block: *containing_block,
|
containing_block: *containing_block,
|
||||||
fragment: self,
|
fragment: self,
|
||||||
|
@ -149,17 +180,34 @@ impl BoxFragment {
|
||||||
return Some(StackingContextType::Real);
|
return Some(StackingContextType::Real);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.style.get_box().position != ComputedPosition::Static {
|
let box_style = &self.style.get_box();
|
||||||
|
if box_style.position != ComputedPosition::Static {
|
||||||
return Some(StackingContextType::PseudoPositioned);
|
return Some(StackingContextType::PseudoPositioned);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.style.get_box().float != ComputedFloat::None {
|
if box_style.float != ComputedFloat::None {
|
||||||
return Some(StackingContextType::PseudoFloat);
|
return Some(StackingContextType::PseudoFloat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if box_style.display.is_atomic_inline_level() {
|
||||||
|
return Some(StackingContextType::PseudoAtomicInline);
|
||||||
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_stacking_context_section(&self) -> StackingContextSection {
|
||||||
|
if self.get_stacking_context_type().is_some() {
|
||||||
|
return StackingContextSection::BackgroundsAndBorders;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.style.get_box().display.outside() == DisplayOutside::Inline {
|
||||||
|
return StackingContextSection::Content;
|
||||||
|
}
|
||||||
|
|
||||||
|
StackingContextSection::BlockBackgroundsAndBorders
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if this fragment establishes a new stacking context and false otherwise.
|
/// Returns true if this fragment establishes a new stacking context and false otherwise.
|
||||||
fn establishes_stacking_context(&self) -> bool {
|
fn establishes_stacking_context(&self) -> bool {
|
||||||
if self.style.get_effects().opacity != 1.0 {
|
if self.style.get_effects().opacity != 1.0 {
|
||||||
|
@ -250,19 +298,21 @@ impl BoxFragment {
|
||||||
&mut child_stacking_context,
|
&mut child_stacking_context,
|
||||||
);
|
);
|
||||||
|
|
||||||
if context_type == StackingContextType::Real {
|
let mut stolen_children = vec![];
|
||||||
child_stacking_context.sort_stacking_contexts();
|
if context_type != StackingContextType::Real {
|
||||||
stacking_context
|
stolen_children = mem::replace(
|
||||||
.stacking_contexts
|
&mut child_stacking_context.stacking_contexts,
|
||||||
.push(child_stacking_context);
|
stolen_children,
|
||||||
} else {
|
);
|
||||||
let mut children =
|
|
||||||
mem::replace(&mut child_stacking_context.stacking_contexts, Vec::new());
|
|
||||||
stacking_context
|
|
||||||
.stacking_contexts
|
|
||||||
.push(child_stacking_context);
|
|
||||||
stacking_context.stacking_contexts.append(&mut children);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
child_stacking_context.sort();
|
||||||
|
stacking_context
|
||||||
|
.stacking_contexts
|
||||||
|
.push(child_stacking_context);
|
||||||
|
stacking_context
|
||||||
|
.stacking_contexts
|
||||||
|
.append(&mut stolen_children);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,6 +325,7 @@ impl BoxFragment {
|
||||||
) {
|
) {
|
||||||
stacking_context.fragments.push(StackingContextFragment {
|
stacking_context.fragments.push(StackingContextFragment {
|
||||||
space_and_clip: builder.current_space_and_clip,
|
space_and_clip: builder.current_space_and_clip,
|
||||||
|
section: self.get_stacking_context_section(),
|
||||||
containing_block: *containing_block,
|
containing_block: *containing_block,
|
||||||
fragment,
|
fragment,
|
||||||
});
|
});
|
||||||
|
|
|
@ -191,7 +191,7 @@ impl FragmentTreeRoot {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
stacking_context.sort_stacking_contexts();
|
stacking_context.sort();
|
||||||
stacking_context.build_display_list(builder);
|
stacking_context.build_display_list(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[stack-floats-003.xht]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[stack-floats-004.xht]
|
|
||||||
expected: FAIL
|
|
Loading…
Add table
Add a link
Reference in a new issue