mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Auto merge of #25862 - mrobinson:transforms-containing-block, r=pcwalton,nox
Have transforms and filters be CBs for all descendants in layout_2020 This is a feature that was never properly implemented in the previous layout system. We still need to preserve their in-tree order in the display list though. <!-- 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 OR - [ ] 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. -->
This commit is contained in:
commit
19323e8f28
16 changed files with 354 additions and 217 deletions
|
@ -37,7 +37,12 @@ type ItemTag = (u64, u16);
|
|||
type HitInfo = Option<ItemTag>;
|
||||
|
||||
pub struct DisplayListBuilder<'a> {
|
||||
/// The current SpatialId and ClipId information for this `DisplayListBuilder`.
|
||||
current_space_and_clip: wr::SpaceAndClipInfo,
|
||||
|
||||
/// The id of the nearest ancestor reference frame for this `DisplayListBuilder`.
|
||||
nearest_reference_frame: wr::SpatialId,
|
||||
|
||||
pub context: &'a LayoutContext<'a>,
|
||||
pub wr: wr::DisplayListBuilder,
|
||||
|
||||
|
@ -56,6 +61,7 @@ impl<'a> DisplayListBuilder<'a> {
|
|||
) -> Self {
|
||||
Self {
|
||||
current_space_and_clip: wr::SpaceAndClipInfo::root_scroll(pipeline_id),
|
||||
nearest_reference_frame: wr::SpatialId::root_reference_frame(pipeline_id),
|
||||
is_contentful: false,
|
||||
context,
|
||||
wr: wr::DisplayListBuilder::new(pipeline_id, viewport_size),
|
||||
|
@ -68,9 +74,14 @@ impl<'a> DisplayListBuilder<'a> {
|
|||
}
|
||||
|
||||
fn clipping_and_scrolling_scope<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||
let previous = self.current_space_and_clip;
|
||||
let previous_space_and_clip = self.current_space_and_clip;
|
||||
let previous_nearest_reference_frame = self.nearest_reference_frame;
|
||||
|
||||
let result = f(self);
|
||||
self.current_space_and_clip = previous;
|
||||
|
||||
self.current_space_and_clip = previous_space_and_clip;
|
||||
self.nearest_reference_frame = previous_nearest_reference_frame;
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use crate::display_list::conversions::ToWebRender;
|
|||
use crate::display_list::DisplayListBuilder;
|
||||
use crate::fragments::{AnonymousFragment, BoxFragment, Fragment};
|
||||
use crate::geom::PhysicalRect;
|
||||
use crate::style_ext::ComputedValuesExt;
|
||||
use euclid::default::Rect;
|
||||
use gfx_traits::{combine_id_with_fragment_type, FragmentType};
|
||||
use std::cmp::Ordering;
|
||||
|
@ -14,7 +15,6 @@ 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;
|
||||
use style::computed_values::position::T as ComputedPosition;
|
||||
use style::computed_values::transform_style::T as ComputedTransformStyle;
|
||||
use style::values::computed::Length;
|
||||
use style::values::generics::box_::Perspective;
|
||||
use style::values::generics::transform;
|
||||
|
@ -96,7 +96,7 @@ impl<'a> StackingContext<'a> {
|
|||
|
||||
fn z_index(&self) -> i32 {
|
||||
match self.initializing_fragment {
|
||||
Some(fragment) => fragment.effective_z_index(),
|
||||
Some(fragment) => fragment.style.effective_z_index(),
|
||||
None => 0,
|
||||
}
|
||||
}
|
||||
|
@ -259,7 +259,7 @@ impl Fragment {
|
|||
|
||||
impl BoxFragment {
|
||||
fn get_stacking_context_type(&self) -> Option<StackingContextType> {
|
||||
if self.establishes_stacking_context() {
|
||||
if self.style.establishes_stacking_context() {
|
||||
return Some(StackingContextType::Real);
|
||||
}
|
||||
|
||||
|
@ -291,68 +291,6 @@ impl BoxFragment {
|
|||
StackingContextSection::BlockBackgroundsAndBorders
|
||||
}
|
||||
|
||||
/// Returns true if this fragment establishes a new stacking context and false otherwise.
|
||||
fn establishes_stacking_context(&self) -> bool {
|
||||
let effects = self.style.get_effects();
|
||||
if effects.opacity != 1.0 {
|
||||
return true;
|
||||
}
|
||||
|
||||
if effects.mix_blend_mode != ComputedMixBlendMode::Normal {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.has_transform_or_perspective() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if !self.style.get_effects().filter.0.is_empty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.style.get_box().transform_style == ComputedTransformStyle::Preserve3d ||
|
||||
self.style.overrides_transform_style()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fixed position and sticky position always create stacking contexts.
|
||||
// TODO(mrobinson): We need to handle sticky positioning here when we support it.
|
||||
if self.style.get_box().position == ComputedPosition::Fixed {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Statically positioned fragments don't establish stacking contexts if the previous
|
||||
// conditions are not fulfilled. Furthermore, z-index doesn't apply to statically
|
||||
// positioned fragments.
|
||||
if self.style.get_box().position == ComputedPosition::Static {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For absolutely and relatively positioned fragments we only establish a stacking
|
||||
// context if there is a z-index set.
|
||||
// See https://www.w3.org/TR/CSS2/visuren.html#z-index
|
||||
!self.style.get_position().z_index.is_auto()
|
||||
}
|
||||
|
||||
// Get the effective z-index of this fragment. Z-indices only apply to positioned element
|
||||
// per CSS 2 9.9.1 (http://www.w3.org/TR/CSS2/visuren.html#z-index), so this value may differ
|
||||
// from the value specified in the style.
|
||||
fn effective_z_index(&self) -> i32 {
|
||||
match self.style.get_box().position {
|
||||
ComputedPosition::Static => {},
|
||||
_ => return self.style.get_position().z_index.integer_or(0),
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
/// Returns true if this fragment has a transform, or perspective property set.
|
||||
fn has_transform_or_perspective(&self) -> bool {
|
||||
!self.style.get_box().transform.0.is_empty() ||
|
||||
self.style.get_box().perspective != Perspective::None
|
||||
}
|
||||
|
||||
fn build_stacking_context_tree<'a>(
|
||||
&'a self,
|
||||
fragment: &'a Fragment,
|
||||
|
@ -452,8 +390,7 @@ impl BoxFragment {
|
|||
// TODO(mrobinson): Eventually this should use the spatial id of the reference
|
||||
// frame that is the parent of this one once we have full support for stacking
|
||||
// contexts and transforms.
|
||||
builder.current_space_and_clip.spatial_id =
|
||||
wr::SpatialId::root_reference_frame(builder.wr.pipeline_id);
|
||||
builder.current_space_and_clip.spatial_id = builder.nearest_reference_frame;
|
||||
}
|
||||
|
||||
fn build_scroll_frame_if_necessary(
|
||||
|
@ -505,7 +442,7 @@ impl BoxFragment {
|
|||
builder: &mut DisplayListBuilder,
|
||||
border_rect: &PhysicalRect<Length>,
|
||||
) -> bool {
|
||||
if !self.has_transform_or_perspective() {
|
||||
if !self.style.has_transform_or_perspective() {
|
||||
return false;
|
||||
}
|
||||
let untyped_border_rect = border_rect.to_untyped();
|
||||
|
@ -535,6 +472,7 @@ impl BoxFragment {
|
|||
wr::PropertyBinding::Value(reference_frame_transform),
|
||||
reference_frame_kind,
|
||||
);
|
||||
builder.nearest_reference_frame = builder.current_space_and_clip.spatial_id;
|
||||
true
|
||||
}
|
||||
|
||||
|
|
|
@ -223,7 +223,8 @@ fn layout_block_level_children<'a>(
|
|||
})
|
||||
.collect()
|
||||
} else {
|
||||
let has_positioned_ancestor = positioning_context.has_positioned_ancestor();
|
||||
let collects_for_nearest_positioned_ancestor =
|
||||
positioning_context.collects_for_nearest_positioned_ancestor();
|
||||
let mut fragments = child_boxes
|
||||
.par_iter()
|
||||
.enumerate()
|
||||
|
@ -238,7 +239,7 @@ fn layout_block_level_children<'a>(
|
|||
/* float_context = */ None,
|
||||
)
|
||||
},
|
||||
|| PositioningContext::new_for_rayon(has_positioned_ancestor),
|
||||
|| PositioningContext::new_for_rayon(collects_for_nearest_positioned_ancestor),
|
||||
PositioningContext::append,
|
||||
)
|
||||
.collect();
|
||||
|
@ -275,7 +276,7 @@ impl BlockLevelBox {
|
|||
tag,
|
||||
style,
|
||||
contents,
|
||||
} => Fragment::Box(positioning_context.for_maybe_position_relative(
|
||||
} => Fragment::Box(positioning_context.layout_maybe_position_relative_fragment(
|
||||
layout_context,
|
||||
containing_block,
|
||||
style,
|
||||
|
@ -293,7 +294,7 @@ impl BlockLevelBox {
|
|||
},
|
||||
)),
|
||||
BlockLevelBox::Independent(contents) => {
|
||||
Fragment::Box(positioning_context.for_maybe_position_relative(
|
||||
Fragment::Box(positioning_context.layout_maybe_position_relative_fragment(
|
||||
layout_context,
|
||||
containing_block,
|
||||
&contents.style,
|
||||
|
@ -326,8 +327,7 @@ impl BlockLevelBox {
|
|||
))
|
||||
},
|
||||
BlockLevelBox::OutOfFlowFloatBox(_box_) => {
|
||||
// FIXME: call for_maybe_position_relative here
|
||||
// TODO
|
||||
// FIXME: call layout_maybe_position_relative_fragment here
|
||||
Fragment::Anonymous(AnonymousFragment::no_op(
|
||||
containing_block.style.writing_mode,
|
||||
))
|
||||
|
|
|
@ -137,7 +137,8 @@ impl BoxTreeRoot {
|
|||
};
|
||||
|
||||
let dummy_tree_rank = 0;
|
||||
let mut positioning_context = PositioningContext::new_for_initial_containing_block();
|
||||
let mut positioning_context =
|
||||
PositioningContext::new_for_containing_block_for_all_descendants();
|
||||
let mut independent_layout = self.0.layout(
|
||||
layout_context,
|
||||
&mut positioning_context,
|
||||
|
@ -145,7 +146,7 @@ impl BoxTreeRoot {
|
|||
dummy_tree_rank,
|
||||
);
|
||||
|
||||
positioning_context.layout_in_initial_containing_block(
|
||||
positioning_context.layout_initial_containing_block_children(
|
||||
layout_context,
|
||||
&initial_containing_block,
|
||||
&mut independent_layout.fragments,
|
||||
|
|
|
@ -25,7 +25,12 @@ pub(crate) struct AbsolutelyPositionedBox {
|
|||
|
||||
pub(crate) struct PositioningContext<'box_tree> {
|
||||
for_nearest_positioned_ancestor: Option<Vec<HoistedAbsolutelyPositionedBox<'box_tree>>>,
|
||||
for_initial_containing_block: Vec<HoistedAbsolutelyPositionedBox<'box_tree>>,
|
||||
|
||||
// For nearest `containing block for all descendants` as defined by the CSS transforms
|
||||
// spec.
|
||||
// https://www.w3.org/TR/css-transforms-1/#containing-block-for-all-descendants
|
||||
for_nearest_containing_block_for_all_descendants:
|
||||
Vec<HoistedAbsolutelyPositionedBox<'box_tree>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -127,62 +132,158 @@ impl AbsolutelyPositionedBox {
|
|||
}
|
||||
|
||||
impl<'box_tree> PositioningContext<'box_tree> {
|
||||
pub(crate) fn new_for_initial_containing_block() -> Self {
|
||||
pub(crate) fn new_for_containing_block_for_all_descendants() -> Self {
|
||||
Self {
|
||||
for_nearest_positioned_ancestor: None,
|
||||
for_initial_containing_block: Vec::new(),
|
||||
for_nearest_containing_block_for_all_descendants: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_for_rayon(has_positioned_ancestor: bool) -> Self {
|
||||
pub(crate) fn new_for_rayon(collects_for_nearest_positioned_ancestor: bool) -> Self {
|
||||
Self {
|
||||
for_nearest_positioned_ancestor: if has_positioned_ancestor {
|
||||
for_nearest_positioned_ancestor: if collects_for_nearest_positioned_ancestor {
|
||||
Some(Vec::new())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
for_initial_containing_block: Vec::new(),
|
||||
for_nearest_containing_block_for_all_descendants: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn has_positioned_ancestor(&self) -> bool {
|
||||
pub(crate) fn collects_for_nearest_positioned_ancestor(&self) -> bool {
|
||||
self.for_nearest_positioned_ancestor.is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn for_maybe_position_relative(
|
||||
/// Given `fragment_layout_fn`, a closure which lays out a fragment in a provided
|
||||
/// `PositioningContext`, create a new positioning context if necessary for the fragment and
|
||||
/// lay out the fragment and all its children. Returns the newly created `BoxFragment`.
|
||||
pub(crate) fn layout_maybe_position_relative_fragment(
|
||||
&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
containing_block: &ContainingBlock,
|
||||
style: &ComputedValues,
|
||||
f: impl FnOnce(&mut Self) -> BoxFragment,
|
||||
fragment_layout_fn: impl FnOnce(&mut Self) -> BoxFragment,
|
||||
) -> BoxFragment {
|
||||
debug_assert!(style.clone_position() != Position::Fixed);
|
||||
debug_assert!(style.clone_position() != Position::Absolute);
|
||||
|
||||
if style.establishes_containing_block_for_all_descendants() {
|
||||
let mut fragment = Self::layout_containing_block_for_all_descendants(
|
||||
layout_context,
|
||||
fragment_layout_fn,
|
||||
);
|
||||
if style.clone_position() == Position::Relative {
|
||||
let mut fragment =
|
||||
// Establing a containing block for absolutely positioned descendants
|
||||
Self::for_positioned(layout_context, &mut self.for_initial_containing_block, f);
|
||||
fragment.content_rect.start_corner +=
|
||||
&relative_adjustement(style, containing_block);
|
||||
}
|
||||
return fragment;
|
||||
}
|
||||
|
||||
if style.clone_position() == Position::Relative {
|
||||
let mut fragment = Self::create_and_layout_positioned(
|
||||
layout_context,
|
||||
style,
|
||||
&mut self.for_nearest_containing_block_for_all_descendants,
|
||||
fragment_layout_fn,
|
||||
);
|
||||
fragment.content_rect.start_corner += &relative_adjustement(style, containing_block);
|
||||
fragment
|
||||
} else {
|
||||
f(self)
|
||||
}
|
||||
return fragment;
|
||||
}
|
||||
|
||||
fn for_positioned(
|
||||
// We don't need to create a new PositioningContext for this Fragment, so
|
||||
// we pass in the current one to the fragment layout closure.
|
||||
fragment_layout_fn(self)
|
||||
}
|
||||
|
||||
/// Given `fragment_layout_fn`, a closure which lays out a fragment in a provided
|
||||
/// `PositioningContext`, create a positioning context a positioned fragment and lay out the
|
||||
/// fragment and all its children. Returns the resulting `BoxFragment`.
|
||||
fn create_and_layout_positioned(
|
||||
layout_context: &LayoutContext,
|
||||
for_initial_containing_block: &mut Vec<HoistedAbsolutelyPositionedBox<'box_tree>>,
|
||||
f: impl FnOnce(&mut Self) -> BoxFragment,
|
||||
style: &ComputedValues,
|
||||
for_nearest_containing_block_for_all_descendants: &mut Vec<
|
||||
HoistedAbsolutelyPositionedBox<'box_tree>,
|
||||
>,
|
||||
fragment_layout_fn: impl FnOnce(&mut Self) -> BoxFragment,
|
||||
) -> BoxFragment {
|
||||
if style.establishes_containing_block_for_all_descendants() {
|
||||
return Self::layout_containing_block_for_all_descendants(
|
||||
layout_context,
|
||||
fragment_layout_fn,
|
||||
);
|
||||
}
|
||||
|
||||
let mut new = Self {
|
||||
for_nearest_positioned_ancestor: Some(Vec::new()),
|
||||
for_initial_containing_block: std::mem::take(for_initial_containing_block),
|
||||
for_nearest_containing_block_for_all_descendants: std::mem::take(
|
||||
for_nearest_containing_block_for_all_descendants,
|
||||
),
|
||||
};
|
||||
let mut positioned_box_fragment = f(&mut new);
|
||||
new.layout_in_positioned_ancestor(layout_context, &mut positioned_box_fragment);
|
||||
*for_initial_containing_block = new.for_initial_containing_block;
|
||||
let mut positioned_box_fragment = fragment_layout_fn(&mut new);
|
||||
new.layout_positioned_fragment_children(layout_context, &mut positioned_box_fragment);
|
||||
*for_nearest_containing_block_for_all_descendants =
|
||||
new.for_nearest_containing_block_for_all_descendants;
|
||||
positioned_box_fragment
|
||||
}
|
||||
|
||||
/// Given `fragment_layout_fn`, a closure which lays out a fragment in a provided
|
||||
/// `PositioningContext`, create a positioning context for a fragment that establishes a
|
||||
/// containing block for all descendants and lay out the fragment and all its children using
|
||||
/// the new positioning context. Returns the resulting `BoxFragment`.
|
||||
fn layout_containing_block_for_all_descendants(
|
||||
layout_context: &LayoutContext,
|
||||
fragment_layout_fn: impl FnOnce(&mut Self) -> BoxFragment,
|
||||
) -> BoxFragment {
|
||||
let mut containing_block_for_all_descendants =
|
||||
Self::new_for_containing_block_for_all_descendants();
|
||||
debug_assert!(containing_block_for_all_descendants
|
||||
.for_nearest_positioned_ancestor
|
||||
.is_none());
|
||||
|
||||
let mut new_fragment = fragment_layout_fn(&mut containing_block_for_all_descendants);
|
||||
|
||||
let padding_rect = Rect {
|
||||
size: new_fragment.content_rect.size.clone(),
|
||||
// Ignore the content rect’s position in its own containing block:
|
||||
start_corner: Vec2::zero(),
|
||||
}
|
||||
.inflate(&new_fragment.padding);
|
||||
let containing_block = DefiniteContainingBlock {
|
||||
size: padding_rect.size.clone(),
|
||||
style: &new_fragment.style,
|
||||
};
|
||||
|
||||
// Loop because it’s possible that we discover (the static position of)
|
||||
// more absolutely-positioned boxes while doing layout for others.
|
||||
let mut new_child_fragments = Vec::new();
|
||||
while !containing_block_for_all_descendants
|
||||
.for_nearest_containing_block_for_all_descendants
|
||||
.is_empty()
|
||||
{
|
||||
HoistedAbsolutelyPositionedBox::layout_many(
|
||||
layout_context,
|
||||
&std::mem::take(
|
||||
&mut containing_block_for_all_descendants
|
||||
.for_nearest_containing_block_for_all_descendants,
|
||||
),
|
||||
&mut new_child_fragments,
|
||||
&mut containing_block_for_all_descendants
|
||||
.for_nearest_containing_block_for_all_descendants,
|
||||
&containing_block,
|
||||
)
|
||||
}
|
||||
|
||||
new_fragment
|
||||
.children
|
||||
.push(Fragment::Anonymous(AnonymousFragment::new(
|
||||
padding_rect,
|
||||
new_child_fragments,
|
||||
new_fragment.style.writing_mode,
|
||||
)));
|
||||
|
||||
new_fragment
|
||||
}
|
||||
|
||||
pub(crate) fn push(&mut self, box_: HoistedAbsolutelyPositionedBox<'box_tree>) {
|
||||
if let Some(nearest) = &mut self.for_nearest_positioned_ancestor {
|
||||
match box_
|
||||
|
@ -196,13 +297,14 @@ impl<'box_tree> PositioningContext<'box_tree> {
|
|||
Position::Static | Position::Relative => unreachable!(),
|
||||
}
|
||||
}
|
||||
self.for_initial_containing_block.push(box_)
|
||||
self.for_nearest_containing_block_for_all_descendants
|
||||
.push(box_)
|
||||
}
|
||||
|
||||
pub(crate) fn append(&mut self, other: Self) {
|
||||
vec_append_owned(
|
||||
&mut self.for_initial_containing_block,
|
||||
other.for_initial_containing_block,
|
||||
&mut self.for_nearest_containing_block_for_all_descendants,
|
||||
other.for_nearest_containing_block_for_all_descendants,
|
||||
);
|
||||
match (
|
||||
self.for_nearest_positioned_ancestor.as_mut(),
|
||||
|
@ -219,7 +321,8 @@ impl<'box_tree> PositioningContext<'box_tree> {
|
|||
tree_rank_in_parent: usize,
|
||||
f: impl FnOnce(&mut Self) -> Vec<Fragment>,
|
||||
) -> Vec<Fragment> {
|
||||
let for_icb_so_far = self.for_initial_containing_block.len();
|
||||
let for_containing_block_for_all_descendants =
|
||||
self.for_nearest_containing_block_for_all_descendants.len();
|
||||
let for_nearest_so_far = self
|
||||
.for_nearest_positioned_ancestor
|
||||
.as_ref()
|
||||
|
@ -228,7 +331,8 @@ impl<'box_tree> PositioningContext<'box_tree> {
|
|||
let fragments = f(self);
|
||||
|
||||
adjust_static_positions(
|
||||
&mut self.for_initial_containing_block[for_icb_so_far..],
|
||||
&mut self.for_nearest_containing_block_for_all_descendants
|
||||
[for_containing_block_for_all_descendants..],
|
||||
&fragments,
|
||||
tree_rank_in_parent,
|
||||
);
|
||||
|
@ -242,7 +346,7 @@ impl<'box_tree> PositioningContext<'box_tree> {
|
|||
fragments
|
||||
}
|
||||
|
||||
pub(crate) fn layout_in_initial_containing_block(
|
||||
pub(crate) fn layout_initial_containing_block_children(
|
||||
&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
initial_containing_block: &DefiniteContainingBlock,
|
||||
|
@ -252,18 +356,21 @@ impl<'box_tree> PositioningContext<'box_tree> {
|
|||
|
||||
// Loop because it’s possible that we discover (the static position of)
|
||||
// more absolutely-positioned boxes while doing layout for others.
|
||||
while !self.for_initial_containing_block.is_empty() {
|
||||
while !self
|
||||
.for_nearest_containing_block_for_all_descendants
|
||||
.is_empty()
|
||||
{
|
||||
HoistedAbsolutelyPositionedBox::layout_many(
|
||||
layout_context,
|
||||
&std::mem::take(&mut self.for_initial_containing_block),
|
||||
&std::mem::take(&mut self.for_nearest_containing_block_for_all_descendants),
|
||||
fragments,
|
||||
&mut self.for_initial_containing_block,
|
||||
&mut self.for_nearest_containing_block_for_all_descendants,
|
||||
initial_containing_block,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_in_positioned_ancestor(
|
||||
fn layout_positioned_fragment_children(
|
||||
&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
positioned_box_fragment: &mut BoxFragment,
|
||||
|
@ -285,7 +392,7 @@ impl<'box_tree> PositioningContext<'box_tree> {
|
|||
layout_context,
|
||||
&for_here,
|
||||
&mut children,
|
||||
&mut self.for_initial_containing_block,
|
||||
&mut self.for_nearest_containing_block_for_all_descendants,
|
||||
&containing_block,
|
||||
);
|
||||
positioned_box_fragment
|
||||
|
@ -304,16 +411,18 @@ impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> {
|
|||
layout_context: &LayoutContext,
|
||||
boxes: &[Self],
|
||||
fragments: &mut Vec<Fragment>,
|
||||
for_initial_containing_block: &mut Vec<HoistedAbsolutelyPositionedBox<'box_tree>>,
|
||||
for_nearest_containing_block_for_all_descendants: &mut Vec<
|
||||
HoistedAbsolutelyPositionedBox<'box_tree>,
|
||||
>,
|
||||
containing_block: &DefiniteContainingBlock,
|
||||
) {
|
||||
if layout_context.use_rayon {
|
||||
fragments.par_extend(boxes.par_iter().mapfold_reduce_into(
|
||||
for_initial_containing_block,
|
||||
|for_initial_containing_block, box_| {
|
||||
for_nearest_containing_block_for_all_descendants,
|
||||
|for_nearest_containing_block_for_all_descendants, box_| {
|
||||
Fragment::Box(box_.layout(
|
||||
layout_context,
|
||||
for_initial_containing_block,
|
||||
for_nearest_containing_block_for_all_descendants,
|
||||
containing_block,
|
||||
))
|
||||
},
|
||||
|
@ -324,7 +433,7 @@ impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> {
|
|||
fragments.extend(boxes.iter().map(|box_| {
|
||||
Fragment::Box(box_.layout(
|
||||
layout_context,
|
||||
for_initial_containing_block,
|
||||
for_nearest_containing_block_for_all_descendants,
|
||||
containing_block,
|
||||
))
|
||||
}))
|
||||
|
@ -334,7 +443,9 @@ impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> {
|
|||
pub(crate) fn layout(
|
||||
&self,
|
||||
layout_context: &LayoutContext,
|
||||
for_initial_containing_block: &mut Vec<HoistedAbsolutelyPositionedBox<'box_tree>>,
|
||||
for_nearest_containing_block_for_all_descendants: &mut Vec<
|
||||
HoistedAbsolutelyPositionedBox<'box_tree>,
|
||||
>,
|
||||
containing_block: &DefiniteContainingBlock,
|
||||
) -> BoxFragment {
|
||||
let style = &self.absolutely_positioned_box.contents.style;
|
||||
|
@ -396,8 +507,13 @@ impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> {
|
|||
block_end: block_axis.margin_end,
|
||||
};
|
||||
|
||||
let for_icb = for_initial_containing_block;
|
||||
PositioningContext::for_positioned(layout_context, for_icb, |positioning_context| {
|
||||
let for_containing_block_for_all_descendants =
|
||||
for_nearest_containing_block_for_all_descendants;
|
||||
PositioningContext::create_and_layout_positioned(
|
||||
layout_context,
|
||||
style,
|
||||
for_containing_block_for_all_descendants,
|
||||
|positioning_context| {
|
||||
let size;
|
||||
let fragments;
|
||||
match self.absolutely_positioned_box.contents.as_replaced() {
|
||||
|
@ -416,7 +532,9 @@ impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> {
|
|||
Anchor::Start(start) => {
|
||||
cbis - start - pb.inline_sum() - margin.inline_sum()
|
||||
},
|
||||
Anchor::End(end) => cbis - end - pb.inline_sum() - margin.inline_sum(),
|
||||
Anchor::End(end) => {
|
||||
cbis - end - pb.inline_sum() - margin.inline_sum()
|
||||
},
|
||||
};
|
||||
self.absolutely_positioned_box
|
||||
.contents
|
||||
|
@ -455,7 +573,9 @@ impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> {
|
|||
|
||||
let inline_start = match inline_axis.anchor {
|
||||
Anchor::Start(start) => start + pb.inline_start + margin.inline_start,
|
||||
Anchor::End(end) => cbis - end - pb.inline_end - margin.inline_end - size.inline,
|
||||
Anchor::End(end) => {
|
||||
cbis - end - pb.inline_end - margin.inline_end - size.inline
|
||||
},
|
||||
};
|
||||
let block_start = match block_axis.anchor {
|
||||
Anchor::Start(start) => start + pb.block_start + margin.block_start,
|
||||
|
@ -480,7 +600,8 @@ impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> {
|
|||
margin,
|
||||
CollapsedBlockMargins::zero(),
|
||||
)
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,13 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::geom::{flow_relative, PhysicalSides, PhysicalSize};
|
||||
use style::computed_values::mix_blend_mode::T as ComputedMixBlendMode;
|
||||
use style::computed_values::position::T as ComputedPosition;
|
||||
use style::computed_values::transform_style::T as ComputedTransformStyle;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::{Length, LengthPercentage, LengthPercentageOrAuto};
|
||||
use style::values::computed::{NonNegativeLengthPercentage, Size};
|
||||
use style::values::generics::box_::Perspective;
|
||||
use style::values::generics::length::MaxSize;
|
||||
use style::values::specified::box_ as stylo;
|
||||
|
||||
|
@ -49,6 +53,10 @@ pub(crate) trait ComputedValuesExt {
|
|||
fn padding(&self) -> flow_relative::Sides<LengthPercentage>;
|
||||
fn border_width(&self) -> flow_relative::Sides<Length>;
|
||||
fn margin(&self) -> flow_relative::Sides<LengthPercentageOrAuto>;
|
||||
fn has_transform_or_perspective(&self) -> bool;
|
||||
fn effective_z_index(&self) -> i32;
|
||||
fn establishes_stacking_context(&self) -> bool;
|
||||
fn establishes_containing_block_for_all_descendants(&self) -> bool;
|
||||
}
|
||||
|
||||
impl ComputedValuesExt for ComputedValues {
|
||||
|
@ -165,6 +173,80 @@ impl ComputedValuesExt for ComputedValues {
|
|||
self.writing_mode,
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns true if this style has a transform, or perspective property set.
|
||||
fn has_transform_or_perspective(&self) -> bool {
|
||||
!self.get_box().transform.0.is_empty() || self.get_box().perspective != Perspective::None
|
||||
}
|
||||
|
||||
/// Get the effective z-index of this fragment. Z-indices only apply to positioned elements
|
||||
/// per CSS 2 9.9.1 (http://www.w3.org/TR/CSS2/visuren.html#z-index), so this value may differ
|
||||
/// from the value specified in the style.
|
||||
fn effective_z_index(&self) -> i32 {
|
||||
match self.get_box().position {
|
||||
ComputedPosition::Static => 0,
|
||||
_ => self.get_position().z_index.integer_or(0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this fragment establishes a new stacking context and false otherwise.
|
||||
fn establishes_stacking_context(&self) -> bool {
|
||||
let effects = self.get_effects();
|
||||
if effects.opacity != 1.0 {
|
||||
return true;
|
||||
}
|
||||
|
||||
if effects.mix_blend_mode != ComputedMixBlendMode::Normal {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.has_transform_or_perspective() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if !self.get_effects().filter.0.is_empty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.get_box().transform_style == ComputedTransformStyle::Preserve3d ||
|
||||
self.overrides_transform_style()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fixed position and sticky position always create stacking contexts.
|
||||
// TODO(mrobinson): We need to handle sticky positioning here when we support it.
|
||||
if self.get_box().position == ComputedPosition::Fixed {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Statically positioned fragments don't establish stacking contexts if the previous
|
||||
// conditions are not fulfilled. Furthermore, z-index doesn't apply to statically
|
||||
// positioned fragments.
|
||||
if self.get_box().position == ComputedPosition::Static {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For absolutely and relatively positioned fragments we only establish a stacking
|
||||
// context if there is a z-index set.
|
||||
// See https://www.w3.org/TR/CSS2/visuren.html#z-index
|
||||
!self.get_position().z_index.is_auto()
|
||||
}
|
||||
|
||||
/// Returns true if this style establishes a containing block for all descendants
|
||||
/// including fixed and absolutely positioned ones.
|
||||
fn establishes_containing_block_for_all_descendants(&self) -> bool {
|
||||
if self.has_transform_or_perspective() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if !self.get_effects().filter.0.is_empty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: We need to handle CSS Contain here.
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl From<stylo::Display> for Display {
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[preserve3d-button.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[transform-abspos-001.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[transform-abspos-002.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[transform-abspos-003.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[transform-abspos-004.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[transform-abspos-006.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[transform-abspos-007.html]
|
||||
expected: FAIL
|
|
@ -0,0 +1,2 @@
|
|||
[filtered-inline-is-container.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[transform_stacking_context_a.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[translate_clip_nested.html]
|
||||
expected: FAIL
|
Loading…
Add table
Add a link
Reference in a new issue