aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2019-12-13 10:50:58 -0500
committerGitHub <noreply@github.com>2019-12-13 10:50:58 -0500
commit762e67f4867e8b52f20f5a08fa48a56e6ebc97c1 (patch)
tree397b458f0c2c58dd0d0c4db475db5ff64d647315
parent0954871992650c53c6dce3e8b80b705e06e32f90 (diff)
parent6f3c5ce773b4170d8c27c958c0bbf3822bfe452f (diff)
downloadservo-762e67f4867e8b52f20f5a08fa48a56e6ebc97c1.tar.gz
servo-762e67f4867e8b52f20f5a08fa48a56e6ebc97c1.zip
Auto merge of #25273 - servo:fixedpos, r=nox
Layout `position: fixed` in the initial containing block
-rw-r--r--Cargo.lock4
-rw-r--r--components/layout_2020/Cargo.toml2
-rw-r--r--components/layout_2020/flow/construct.rs30
-rw-r--r--components/layout_2020/flow/inline.rs38
-rw-r--r--components/layout_2020/flow/mod.rs316
-rw-r--r--components/layout_2020/flow/root.rs24
-rw-r--r--components/layout_2020/formatting_contexts.rs6
-rw-r--r--components/layout_2020/lib.rs30
-rw-r--r--components/layout_2020/positioned.rs448
-rw-r--r--components/style/properties/longhands/box.mako.rs3
-rw-r--r--components/style/properties/shorthands/background.mako.rs23
-rw-r--r--tests/wpt/metadata-layout-2020/css/CSS2/box-display/block-in-inline-008.xht.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/css/CSS2/box-display/block-in-inline-relpos-001.xht.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-001.xht.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-002.xht.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-003.xht.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-004.xht.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-005.xht.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-006.xht.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-007.xht.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-008.xht.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-010.xht.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-023.xht.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-026.xht.ini2
24 files changed, 549 insertions, 401 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 51a325d4ffa..418864bc117 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4219,9 +4219,9 @@ dependencies = [
[[package]]
name = "rayon_croissant"
-version = "0.1.1"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b725e815f3aa08718063883a75003336889debafe2f8fa67fbe91563ddc4efa"
+checksum = "3e4aafda434bd10fec689858e2b1d713d0b784b1e60df3761ac8fa727d7e8e27"
dependencies = [
"moite_moite",
"rayon",
diff --git a/components/layout_2020/Cargo.toml b/components/layout_2020/Cargo.toml
index 5a28da8d9ee..1d76d00af79 100644
--- a/components/layout_2020/Cargo.toml
+++ b/components/layout_2020/Cargo.toml
@@ -25,7 +25,7 @@ msg = {path = "../msg"}
net_traits = {path = "../net_traits"}
range = {path = "../range"}
rayon = "1"
-rayon_croissant = "0.1.1"
+rayon_croissant = "0.2.0"
script_layout_interface = {path = "../script_layout_interface"}
script_traits = {path = "../script_traits"}
serde = "1.0"
diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs
index 4a397add2c3..25b401e5592 100644
--- a/components/layout_2020/flow/construct.rs
+++ b/components/layout_2020/flow/construct.rs
@@ -172,14 +172,6 @@ impl BlockContainer {
contains_floats: ContainsFloats,
outer_content_sizes_of_children: ContentSizes,
}
- impl Default for Accumulator {
- fn default() -> Self {
- Self {
- contains_floats: ContainsFloats::No,
- outer_content_sizes_of_children: ContentSizes::zero(),
- }
- }
- }
let mut acc = Accumulator {
contains_floats: builder.contains_floats,
outer_content_sizes_of_children: ContentSizes::zero(),
@@ -199,13 +191,21 @@ impl BlockContainer {
builder
.block_level_boxes
.into_par_iter()
- .mapfold_reduce_into(&mut acc, mapfold, |left, right| {
- left.contains_floats |= right.contains_floats;
- if content_sizes.requests_inline() {
- left.outer_content_sizes_of_children
- .max_assign(&right.outer_content_sizes_of_children)
- }
- })
+ .mapfold_reduce_into(
+ &mut acc,
+ mapfold,
+ || Accumulator {
+ contains_floats: ContainsFloats::No,
+ outer_content_sizes_of_children: ContentSizes::zero(),
+ },
+ |left, right| {
+ left.contains_floats |= right.contains_floats;
+ if content_sizes.requests_inline() {
+ left.outer_content_sizes_of_children
+ .max_assign(&right.outer_content_sizes_of_children)
+ }
+ },
+ )
.collect()
} else {
builder
diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs
index c4b760275d9..93d7d6f8bdc 100644
--- a/components/layout_2020/flow/inline.rs
+++ b/components/layout_2020/flow/inline.rs
@@ -9,10 +9,10 @@ use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::CollapsedBlockMargins;
use crate::fragments::{AnonymousFragment, BoxFragment, Fragment, TextFragment};
use crate::geom::flow_relative::{Rect, Sides, Vec2};
-use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment};
+use crate::positioned::{relative_adjustement, AbsolutelyPositionedBox, PositioningContext};
use crate::sizing::ContentSizes;
use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside};
-use crate::{relative_adjustement, ContainingBlock};
+use crate::ContainingBlock;
use app_units::Au;
use gfx::text::text_run::GlyphRun;
use servo_arc::Arc;
@@ -68,9 +68,9 @@ struct PartialInlineBoxFragment<'box_tree> {
parent_nesting_level: InlineNestingLevelState<'box_tree>,
}
-struct InlineFormattingContextState<'box_tree, 'a> {
- absolutely_positioned_fragments: &'a mut Vec<AbsolutelyPositionedFragment<'box_tree>>,
- containing_block: &'a ContainingBlock<'a>,
+struct InlineFormattingContextState<'box_tree, 'a, 'b> {
+ positioning_context: &'a mut PositioningContext<'box_tree>,
+ containing_block: &'b ContainingBlock<'b>,
lines: Lines,
inline_position: Length,
partial_inline_boxes_stack: Vec<PartialInlineBoxFragment<'box_tree>>,
@@ -195,12 +195,12 @@ impl InlineFormattingContext {
pub(super) fn layout<'a>(
&'a self,
layout_context: &LayoutContext,
+ positioning_context: &mut PositioningContext<'a>,
containing_block: &ContainingBlock,
tree_rank: usize,
- absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
) -> FlowLayout {
let mut ifc = InlineFormattingContextState {
- absolutely_positioned_fragments,
+ positioning_context,
containing_block,
partial_inline_boxes_stack: Vec::new(),
lines: Lines {
@@ -244,7 +244,7 @@ impl InlineFormattingContext {
panic!("display:none does not generate an abspos box")
},
};
- ifc.absolutely_positioned_fragments
+ ifc.positioning_context
.push(box_.layout(initial_start_corner, tree_rank));
},
InlineLevelBox::OutOfFlowFloatBox(_box_) => {
@@ -346,7 +346,7 @@ impl Lines {
impl InlineBox {
fn start_layout<'box_tree>(
&'box_tree self,
- ifc: &mut InlineFormattingContextState<'box_tree, '_>,
+ ifc: &mut InlineFormattingContextState<'box_tree, '_, '_>,
) -> PartialInlineBoxFragment<'box_tree> {
let style = self.style.clone();
let cbis = ifc.containing_block.inline_size;
@@ -367,11 +367,9 @@ impl InlineBox {
block: padding.block_start + border.block_start + margin.block_start,
inline: ifc.inline_position - ifc.current_nesting_level.inline_start,
};
- start_corner += &relative_adjustement(
- &style,
- ifc.containing_block.inline_size,
- ifc.containing_block.block_size,
- );
+ if style.clone_position().is_relative() {
+ start_corner += &relative_adjustement(&style, ifc.containing_block)
+ }
PartialInlineBoxFragment {
style,
start_corner,
@@ -440,7 +438,7 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
fn layout_atomic<'box_tree>(
layout_context: &LayoutContext,
- ifc: &mut InlineFormattingContextState<'box_tree, '_>,
+ ifc: &mut InlineFormattingContextState<'box_tree, '_, '_>,
atomic: &'box_tree IndependentFormattingContext,
) {
let cbis = ifc.containing_block.inline_size;
@@ -457,11 +455,9 @@ fn layout_atomic<'box_tree>(
block: pbm.block_start,
inline: ifc.inline_position - ifc.current_nesting_level.inline_start,
};
- start_corner += &relative_adjustement(
- &atomic.style,
- ifc.containing_block.inline_size,
- ifc.containing_block.block_size,
- );
+ if atomic.style.clone_position().is_relative() {
+ start_corner += &relative_adjustement(&atomic.style, ifc.containing_block)
+ }
let fragment = match atomic.as_replaced() {
Ok(replaced) => {
@@ -521,9 +517,9 @@ fn layout_atomic<'box_tree>(
// FIXME: Do we need to call `adjust_static_positions` somewhere near here?
let independent_layout = non_replaced.layout(
layout_context,
+ ifc.positioning_context,
&containing_block_for_children,
dummy_tree_rank,
- ifc.absolutely_positioned_fragments,
);
// https://drafts.csswg.org/css2/visudet.html#block-root-margin
diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs
index 3e45defb365..64f87ea09d0 100644
--- a/components/layout_2020/flow/mod.rs
+++ b/components/layout_2020/flow/mod.rs
@@ -7,19 +7,17 @@
use crate::context::LayoutContext;
use crate::flow::float::{FloatBox, FloatContext};
use crate::flow::inline::InlineFormattingContext;
-use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout};
+use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout, NonReplacedIFC};
use crate::fragments::{AnonymousFragment, BoxFragment, Fragment};
use crate::fragments::{CollapsedBlockMargins, CollapsedMargin};
use crate::geom::flow_relative::{Rect, Sides, Vec2};
-use crate::positioned::adjust_static_positions;
-use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment};
+use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
use crate::replaced::ReplacedContent;
use crate::style_ext::ComputedValuesExt;
-use crate::{relative_adjustement, ContainingBlock};
+use crate::ContainingBlock;
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
use rayon_croissant::ParallelIteratorExt;
use servo_arc::Arc;
-use style::computed_values::position::T as Position;
use style::properties::ComputedValues;
use style::values::computed::{Length, LengthOrAuto};
use style::Zero;
@@ -67,9 +65,9 @@ impl BlockFormattingContext {
pub(super) fn layout<'a>(
&'a self,
layout_context: &LayoutContext,
+ positioning_context: &mut PositioningContext<'a>,
containing_block: &ContainingBlock,
tree_rank: usize,
- absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
) -> IndependentLayout {
let mut float_context;
let float_context = if self.contains_floats {
@@ -80,9 +78,9 @@ impl BlockFormattingContext {
};
let flow_layout = self.contents.layout(
layout_context,
+ positioning_context,
containing_block,
tree_rank,
- absolutely_positioned_fragments,
float_context,
CollapsibleWithParentStartMargin(false),
);
@@ -103,27 +101,27 @@ impl BlockContainer {
fn layout<'a>(
&'a self,
layout_context: &LayoutContext,
+ positioning_context: &mut PositioningContext<'a>,
containing_block: &ContainingBlock,
tree_rank: usize,
- absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
float_context: Option<&mut FloatContext>,
collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
) -> FlowLayout {
match self {
BlockContainer::BlockLevelBoxes(child_boxes) => layout_block_level_children(
layout_context,
+ positioning_context,
child_boxes,
containing_block,
tree_rank,
- absolutely_positioned_fragments,
float_context,
collapsible_with_parent_start_margin,
),
BlockContainer::InlineFormattingContext(ifc) => ifc.layout(
layout_context,
+ positioning_context,
containing_block,
tree_rank,
- absolutely_positioned_fragments,
),
}
}
@@ -131,10 +129,10 @@ impl BlockContainer {
fn layout_block_level_children<'a>(
layout_context: &LayoutContext,
+ positioning_context: &mut PositioningContext<'a>,
child_boxes: &'a [Arc<BlockLevelBox>],
containing_block: &ContainingBlock,
tree_rank: usize,
- absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
mut float_context: Option<&mut FloatContext>,
collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
) -> FlowLayout {
@@ -194,7 +192,6 @@ fn layout_block_level_children<'a>(
current_block_direction_position: Length,
}
- let abspos_so_far = absolutely_positioned_fragments.len();
let mut placement_state = PlacementState {
next_in_flow_margin_collapses_with_parent_start_margin:
collapsible_with_parent_start_margin.0,
@@ -202,56 +199,52 @@ fn layout_block_level_children<'a>(
current_margin: CollapsedMargin::zero(),
current_block_direction_position: Length::zero(),
};
- let mut fragments: Vec<_>;
- if float_context.is_some() || !layout_context.use_rayon {
- // Because floats are involved, we do layout for this block formatting context
- // in tree order without parallelism. This enables mutable access
- // to a `FloatContext` that tracks every float encountered so far (again in tree order).
- fragments = child_boxes
- .iter()
- .enumerate()
- .map(|(tree_rank, box_)| {
- let mut fragment = box_.layout(
- layout_context,
- containing_block,
- tree_rank,
- absolutely_positioned_fragments,
- float_context.as_mut().map(|c| &mut **c),
- );
- place_block_level_fragment(&mut fragment, &mut placement_state);
- fragment
- })
- .collect()
- } else {
- fragments = child_boxes
- .par_iter()
- .enumerate()
- .mapfold_reduce_into(
- absolutely_positioned_fragments,
- |abspos_fragments, (tree_rank, box_)| {
- box_.layout(
+ let fragments = positioning_context.adjust_static_positions(tree_rank, |positioning_context| {
+ if float_context.is_some() || !layout_context.use_rayon {
+ // Because floats are involved, we do layout for this block formatting context
+ // in tree order without parallelism. This enables mutable access
+ // to a `FloatContext` that tracks every float encountered so far (again in tree order).
+ child_boxes
+ .iter()
+ .enumerate()
+ .map(|(tree_rank, box_)| {
+ let mut fragment = box_.layout(
layout_context,
+ positioning_context,
containing_block,
tree_rank,
- abspos_fragments,
- /* float_context = */ None,
- )
- },
- |left_abspos_fragments, mut right_abspos_fragments| {
- left_abspos_fragments.append(&mut right_abspos_fragments);
- },
- )
- .collect();
- for fragment in &mut fragments {
- place_block_level_fragment(fragment, &mut placement_state)
+ float_context.as_mut().map(|c| &mut **c),
+ );
+ place_block_level_fragment(&mut fragment, &mut placement_state);
+ fragment
+ })
+ .collect()
+ } else {
+ let has_positioned_ancestor = positioning_context.has_positioned_ancestor();
+ let mut fragments = child_boxes
+ .par_iter()
+ .enumerate()
+ .mapfold_reduce_into(
+ positioning_context,
+ |positioning_context, (tree_rank, box_)| {
+ box_.layout(
+ layout_context,
+ positioning_context,
+ containing_block,
+ tree_rank,
+ /* float_context = */ None,
+ )
+ },
+ || PositioningContext::new_for_rayon(has_positioned_ancestor),
+ PositioningContext::append,
+ )
+ .collect();
+ for fragment in &mut fragments {
+ place_block_level_fragment(fragment, &mut placement_state)
+ }
+ fragments
}
- }
-
- adjust_static_positions(
- &mut absolutely_positioned_fragments[abspos_so_far..],
- &mut fragments,
- tree_rank,
- );
+ });
FlowLayout {
fragments,
@@ -269,65 +262,63 @@ impl BlockLevelBox {
fn layout<'a>(
&'a self,
layout_context: &LayoutContext,
+ positioning_context: &mut PositioningContext<'a>,
containing_block: &ContainingBlock,
tree_rank: usize,
- absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
float_context: Option<&mut FloatContext>,
) -> Fragment {
match self {
BlockLevelBox::SameFormattingContextBlock { style, contents } => {
- Fragment::Box(layout_in_flow_non_replaced_block_level(
+ Fragment::Box(positioning_context.for_maybe_position_relative(
layout_context,
containing_block,
- absolutely_positioned_fragments,
style,
- BlockLevelKind::SameFormattingContextBlock,
- |containing_block, nested_abspos, collapsible_with_parent_start_margin| {
- contents.layout(
+ |positioning_context| {
+ layout_in_flow_non_replaced_block_level(
layout_context,
+ positioning_context,
containing_block,
+ style,
+ NonReplacedContents::SameFormattingContextBlock(contents),
tree_rank,
- nested_abspos,
float_context,
- collapsible_with_parent_start_margin,
)
},
))
},
- BlockLevelBox::Independent(contents) => match contents.as_replaced() {
- Ok(replaced) => Fragment::Box(layout_in_flow_replaced_block_level(
- containing_block,
- &contents.style,
- replaced,
- )),
- Err(non_replaced) => Fragment::Box(layout_in_flow_non_replaced_block_level(
+ BlockLevelBox::Independent(contents) => {
+ Fragment::Box(positioning_context.for_maybe_position_relative(
layout_context,
containing_block,
- absolutely_positioned_fragments,
&contents.style,
- BlockLevelKind::EstablishesAnIndependentFormattingContext,
- |containing_block, nested_abspos, _| {
- let independent_layout = non_replaced.layout(
+ |positioning_context| match contents.as_replaced() {
+ Ok(replaced) => layout_in_flow_replaced_block_level(
+ containing_block,
+ &contents.style,
+ replaced,
+ ),
+ Err(non_replaced) => layout_in_flow_non_replaced_block_level(
layout_context,
+ positioning_context,
containing_block,
+ &contents.style,
+ NonReplacedContents::EstablishesAnIndependentFormattingContext(
+ non_replaced,
+ ),
tree_rank,
- nested_abspos,
- );
- FlowLayout {
- fragments: independent_layout.fragments,
- content_block_size: independent_layout.content_block_size,
- collapsible_margins_in_children: CollapsedBlockMargins::zero(),
- }
+ float_context,
+ ),
},
- )),
+ ))
},
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
- absolutely_positioned_fragments.push(box_.layout(Vec2::zero(), tree_rank));
+ positioning_context.push(box_.layout(Vec2::zero(), tree_rank));
Fragment::Anonymous(AnonymousFragment::no_op(
containing_block.style.writing_mode,
))
},
BlockLevelBox::OutOfFlowFloatBox(_box_) => {
+ // FIXME: call for_maybe_position_relative here
// TODO
Fragment::Anonymous(AnonymousFragment::no_op(
containing_block.style.writing_mode,
@@ -337,25 +328,21 @@ impl BlockLevelBox {
}
}
-#[derive(PartialEq)]
-enum BlockLevelKind {
- SameFormattingContextBlock,
- EstablishesAnIndependentFormattingContext,
+enum NonReplacedContents<'a> {
+ SameFormattingContextBlock(&'a BlockContainer),
+ EstablishesAnIndependentFormattingContext(NonReplacedIFC<'a>),
}
/// https://drafts.csswg.org/css2/visudet.html#blockwidth
/// https://drafts.csswg.org/css2/visudet.html#normal-block
fn layout_in_flow_non_replaced_block_level<'a>(
layout_context: &LayoutContext,
+ positioning_context: &mut PositioningContext<'a>,
containing_block: &ContainingBlock,
- absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
style: &Arc<ComputedValues>,
- block_level_kind: BlockLevelKind,
- layout_contents: impl FnOnce(
- &ContainingBlock,
- &mut Vec<AbsolutelyPositionedFragment<'a>>,
- CollapsibleWithParentStartMargin,
- ) -> FlowLayout,
+ block_level_kind: NonReplacedContents<'a>,
+ tree_rank: usize,
+ float_context: Option<&mut FloatContext>,
) -> BoxFragment {
let cbis = containing_block.inline_size;
let padding = style.padding().percentages_relative_to(cbis);
@@ -428,83 +415,81 @@ fn layout_in_flow_non_replaced_block_level<'a>(
"Mixed writing modes are not supported yet"
);
- let this_start_margin_can_collapse_with_children = CollapsibleWithParentStartMargin(
- block_level_kind == BlockLevelKind::SameFormattingContextBlock &&
- pb.block_start == Length::zero(),
- );
- let this_end_margin_can_collapse_with_children = block_size == LengthOrAuto::Auto &&
- min_box_size.block == Length::zero() &&
- pb.block_end == Length::zero() &&
- block_level_kind == BlockLevelKind::SameFormattingContextBlock;
- let mut nested_abspos = vec![];
- let mut flow_layout = layout_contents(
- &containing_block_for_children,
- if style.get_box().position == Position::Relative {
- &mut nested_abspos
- } else {
- absolutely_positioned_fragments
- },
- this_start_margin_can_collapse_with_children,
- );
let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
- if this_start_margin_can_collapse_with_children.0 {
- block_margins_collapsed_with_children
- .start
- .adjoin_assign(&flow_layout.collapsible_margins_in_children.start);
- if flow_layout
- .collapsible_margins_in_children
- .collapsed_through
- {
- block_margins_collapsed_with_children
- .start
- .adjoin_assign(&std::mem::replace(
- &mut flow_layout.collapsible_margins_in_children.end,
- CollapsedMargin::zero(),
- ));
- }
- }
- if this_end_margin_can_collapse_with_children {
- block_margins_collapsed_with_children
- .end
- .adjoin_assign(&flow_layout.collapsible_margins_in_children.end);
- } else {
- flow_layout.content_block_size += flow_layout.collapsible_margins_in_children.end.solve();
- }
- block_margins_collapsed_with_children.collapsed_through =
- this_start_margin_can_collapse_with_children.0 &&
- this_end_margin_can_collapse_with_children &&
- flow_layout
- .collapsible_margins_in_children
- .collapsed_through;
- let relative_adjustement = relative_adjustement(style, inline_size, block_size);
+
+ let fragments;
+ let mut content_block_size;
+ match block_level_kind {
+ NonReplacedContents::SameFormattingContextBlock(contents) => {
+ let this_start_margin_can_collapse_with_children = pb.block_start == Length::zero();
+ let this_end_margin_can_collapse_with_children = pb.block_end == Length::zero() &&
+ block_size == LengthOrAuto::Auto &&
+ min_box_size.block == Length::zero();
+
+ let flow_layout = contents.layout(
+ layout_context,
+ positioning_context,
+ &containing_block_for_children,
+ tree_rank,
+ float_context,
+ CollapsibleWithParentStartMargin(this_start_margin_can_collapse_with_children),
+ );
+ fragments = flow_layout.fragments;
+ content_block_size = flow_layout.content_block_size;
+ let mut collapsible_margins_in_children = flow_layout.collapsible_margins_in_children;
+
+ if this_start_margin_can_collapse_with_children {
+ block_margins_collapsed_with_children
+ .start
+ .adjoin_assign(&collapsible_margins_in_children.start);
+ if collapsible_margins_in_children.collapsed_through {
+ block_margins_collapsed_with_children
+ .start
+ .adjoin_assign(&std::mem::replace(
+ &mut collapsible_margins_in_children.end,
+ CollapsedMargin::zero(),
+ ));
+ }
+ }
+ if this_end_margin_can_collapse_with_children {
+ block_margins_collapsed_with_children
+ .end
+ .adjoin_assign(&collapsible_margins_in_children.end);
+ } else {
+ content_block_size += collapsible_margins_in_children.end.solve();
+ }
+ block_margins_collapsed_with_children.collapsed_through =
+ this_start_margin_can_collapse_with_children &&
+ this_end_margin_can_collapse_with_children &&
+ collapsible_margins_in_children.collapsed_through;
+ },
+ NonReplacedContents::EstablishesAnIndependentFormattingContext(non_replaced) => {
+ let independent_layout = non_replaced.layout(
+ layout_context,
+ positioning_context,
+ &containing_block_for_children,
+ tree_rank,
+ );
+ fragments = independent_layout.fragments;
+ content_block_size = independent_layout.content_block_size;
+ },
+ };
let block_size = block_size.auto_is(|| {
- flow_layout
- .content_block_size
- .clamp_between_extremums(min_box_size.block, max_box_size.block)
+ content_block_size.clamp_between_extremums(min_box_size.block, max_box_size.block)
});
let content_rect = Rect {
start_corner: Vec2 {
- block: pb.block_start + relative_adjustement.block,
- inline: pb.inline_start + relative_adjustement.inline + margin.inline_start,
+ block: pb.block_start,
+ inline: pb.inline_start,
},
size: Vec2 {
block: block_size,
inline: inline_size,
},
};
- if style.get_box().position == Position::Relative {
- AbsolutelyPositionedFragment::in_positioned_containing_block(
- layout_context,
- &nested_abspos,
- &mut flow_layout.fragments,
- &content_rect.size,
- &padding,
- style,
- )
- }
BoxFragment {
style: style.clone(),
- children: flow_layout.fragments,
+ children: fragments,
content_rect,
padding,
border,
@@ -543,15 +528,10 @@ fn layout_in_flow_replaced_block_level<'a>(
block_end: computed_margin.block_end.auto_is(Length::zero),
};
let fragments = replaced.make_fragments(style, size.clone());
- let relative_adjustement = relative_adjustement(
- style,
- size.inline,
- LengthOrAuto::LengthPercentage(size.block),
- );
let content_rect = Rect {
start_corner: Vec2 {
- block: pb.block_start + relative_adjustement.block,
- inline: pb.inline_start + relative_adjustement.inline + margin.inline_start,
+ block: pb.block_start,
+ inline: pb.inline_start + margin.inline_start,
},
size,
};
diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs
index 15dc6d404b6..24dea984e62 100644
--- a/components/layout_2020/flow/root.rs
+++ b/components/layout_2020/flow/root.rs
@@ -12,12 +12,12 @@ use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::Fragment;
use crate::geom;
use crate::geom::flow_relative::Vec2;
-use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment};
+use crate::positioned::AbsolutelyPositionedBox;
+use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent;
use crate::sizing::ContentSizesRequest;
use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside};
use crate::DefiniteContainingBlock;
-use rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator};
use script_layout_interface::wrapper_traits::LayoutNode;
use servo_arc::Arc;
use style::properties::ComputedValues;
@@ -110,25 +110,19 @@ impl BoxTreeRoot {
};
let dummy_tree_rank = 0;
- let mut absolutely_positioned_fragments = vec![];
+ let mut positioning_context = PositioningContext::new_for_initial_containing_block();
let mut independent_layout = self.0.layout(
layout_context,
+ &mut positioning_context,
&(&initial_containing_block).into(),
dummy_tree_rank,
- &mut absolutely_positioned_fragments,
);
- let map =
- |a: &AbsolutelyPositionedFragment| a.layout(layout_context, &initial_containing_block);
- if layout_context.use_rayon {
- independent_layout
- .fragments
- .par_extend(absolutely_positioned_fragments.par_iter().map(map))
- } else {
- independent_layout
- .fragments
- .extend(absolutely_positioned_fragments.iter().map(map))
- }
+ positioning_context.layout_in_initial_containing_block(
+ layout_context,
+ &initial_containing_block,
+ &mut independent_layout.fragments,
+ );
FragmentTreeRoot(independent_layout.fragments)
}
diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs
index eb90d62c926..dcbbfa370a6 100644
--- a/components/layout_2020/formatting_contexts.rs
+++ b/components/layout_2020/formatting_contexts.rs
@@ -6,7 +6,7 @@ use crate::context::LayoutContext;
use crate::dom_traversal::{Contents, NodeExt};
use crate::flow::BlockFormattingContext;
use crate::fragments::Fragment;
-use crate::positioned::AbsolutelyPositionedFragment;
+use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent;
use crate::sizing::{BoxContentSizes, ContentSizesRequest};
use crate::style_ext::DisplayInside;
@@ -101,16 +101,16 @@ impl<'a> NonReplacedIFC<'a> {
pub fn layout(
&self,
layout_context: &LayoutContext,
+ positioning_context: &mut PositioningContext<'a>,
containing_block: &ContainingBlock,
tree_rank: usize,
- absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
) -> IndependentLayout {
match &self.0 {
NonReplacedIFCKind::Flow(bfc) => bfc.layout(
layout_context,
+ positioning_context,
containing_block,
tree_rank,
- absolutely_positioned_fragments,
),
}
}
diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs
index 8e923f870d7..b8cc003caf5 100644
--- a/components/layout_2020/lib.rs
+++ b/components/layout_2020/lib.rs
@@ -27,11 +27,8 @@ pub mod wrapper;
pub use flow::{BoxTreeRoot, FragmentTreeRoot};
use crate::geom::flow_relative::Vec2;
-use crate::style_ext::ComputedValuesExt;
-use style::computed_values::position::T as Position;
use style::properties::ComputedValues;
use style::values::computed::{Length, LengthOrAuto};
-use style::Zero;
struct ContainingBlock<'a> {
inline_size: Length,
@@ -53,30 +50,3 @@ impl<'a> From<&'_ DefiniteContainingBlock<'a>> for ContainingBlock<'a> {
}
}
}
-
-/// https://drafts.csswg.org/css2/visuren.html#relative-positioning
-fn relative_adjustement(
- style: &ComputedValues,
- inline_size: Length,
- block_size: LengthOrAuto,
-) -> Vec2<Length> {
- if style.get_box().position != Position::Relative {
- return Vec2::zero();
- }
- fn adjust(start: LengthOrAuto, end: LengthOrAuto) -> Length {
- match (start, end) {
- (LengthOrAuto::Auto, LengthOrAuto::Auto) => Length::zero(),
- (LengthOrAuto::Auto, LengthOrAuto::LengthPercentage(end)) => -end,
- (LengthOrAuto::LengthPercentage(start), _) => start,
- }
- }
- let block_size = block_size.auto_is(Length::zero);
- let box_offsets = style.box_offsets().map_inline_and_block_axes(
- |v| v.percentage_relative_to(inline_size),
- |v| v.percentage_relative_to(block_size),
- );
- Vec2 {
- inline: adjust(box_offsets.inline_start, box_offsets.inline_end),
- block: adjust(box_offsets.block_start, box_offsets.block_end),
- }
-}
diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs
index b9c64ea54d3..cfe615ae27d 100644
--- a/components/layout_2020/positioned.rs
+++ b/components/layout_2020/positioned.rs
@@ -10,8 +10,10 @@ use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::sizing::ContentSizesRequest;
use crate::style_ext::{ComputedValuesExt, DisplayInside};
use crate::{ContainingBlock, DefiniteContainingBlock};
-use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
+use rayon::iter::{IntoParallelRefIterator, ParallelExtend};
+use rayon_croissant::ParallelIteratorExt;
use servo_arc::Arc;
+use style::computed_values::position::T as Position;
use style::properties::ComputedValues;
use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
use style::Zero;
@@ -21,9 +23,14 @@ pub(crate) struct AbsolutelyPositionedBox {
pub contents: IndependentFormattingContext,
}
+pub(crate) struct PositioningContext<'box_tree> {
+ for_nearest_positioned_ancestor: Option<Vec<HoistedAbsolutelyPositionedBox<'box_tree>>>,
+ for_initial_containing_block: Vec<HoistedAbsolutelyPositionedBox<'box_tree>>,
+}
+
#[derive(Debug)]
-pub(crate) struct AbsolutelyPositionedFragment<'box_> {
- absolutely_positioned_box: &'box_ AbsolutelyPositionedBox,
+pub(crate) struct HoistedAbsolutelyPositionedBox<'box_tree> {
+ absolutely_positioned_box: &'box_tree AbsolutelyPositionedBox,
/// The rank of the child from which this absolutely positioned fragment
/// came from, when doing the layout of a block container. Used to compute
@@ -77,11 +84,11 @@ impl AbsolutelyPositionedBox {
}
}
- pub(crate) fn layout<'a>(
- &'a self,
+ pub(crate) fn layout(
+ &self,
initial_start_corner: Vec2<Length>,
tree_rank: usize,
- ) -> AbsolutelyPositionedFragment {
+ ) -> HoistedAbsolutelyPositionedBox {
fn absolute_box_offsets(
initial_static_start: Length,
start: LengthPercentageOrAuto,
@@ -98,7 +105,7 @@ impl AbsolutelyPositionedBox {
}
let box_offsets = self.contents.style.box_offsets();
- AbsolutelyPositionedFragment {
+ HoistedAbsolutelyPositionedBox {
absolutely_positioned_box: self,
tree_rank,
box_offsets: Vec2 {
@@ -117,46 +124,217 @@ impl AbsolutelyPositionedBox {
}
}
-impl<'a> AbsolutelyPositionedFragment<'a> {
- pub(crate) fn in_positioned_containing_block(
+impl<'box_tree> PositioningContext<'box_tree> {
+ pub(crate) fn new_for_initial_containing_block() -> Self {
+ Self {
+ for_nearest_positioned_ancestor: None,
+ for_initial_containing_block: Vec::new(),
+ }
+ }
+
+ pub(crate) fn new_for_rayon(has_positioned_ancestor: bool) -> Self {
+ Self {
+ for_nearest_positioned_ancestor: if has_positioned_ancestor {
+ Some(Vec::new())
+ } else {
+ None
+ },
+ for_initial_containing_block: Vec::new(),
+ }
+ }
+
+ pub(crate) fn has_positioned_ancestor(&self) -> bool {
+ self.for_nearest_positioned_ancestor.is_some()
+ }
+
+ pub(crate) fn for_maybe_position_relative(
+ &mut self,
layout_context: &LayoutContext,
- absolute: &[Self],
- fragments: &mut Vec<Fragment>,
- content_rect_size: &Vec2<Length>,
- padding: &Sides<Length>,
+ containing_block: &ContainingBlock,
style: &ComputedValues,
+ f: impl FnOnce(&mut Self) -> BoxFragment,
+ ) -> BoxFragment {
+ 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);
+ fragment
+ } else {
+ f(self)
+ }
+ }
+
+ fn for_positioned(
+ layout_context: &LayoutContext,
+ for_initial_containing_block: &mut Vec<HoistedAbsolutelyPositionedBox<'box_tree>>,
+ f: impl FnOnce(&mut Self) -> BoxFragment,
+ ) -> BoxFragment {
+ let mut new = Self {
+ for_nearest_positioned_ancestor: Some(Vec::new()),
+ for_initial_containing_block: std::mem::take(for_initial_containing_block),
+ };
+ 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;
+ positioned_box_fragment
+ }
+
+ pub(crate) fn push(&mut self, box_: HoistedAbsolutelyPositionedBox<'box_tree>) {
+ if let Some(nearest) = &mut self.for_nearest_positioned_ancestor {
+ match box_
+ .absolutely_positioned_box
+ .contents
+ .style
+ .clone_position()
+ {
+ Position::Fixed => {}, // fall through
+ Position::Absolute => return nearest.push(box_),
+ Position::Static | Position::Relative => unreachable!(),
+ }
+ }
+ self.for_initial_containing_block.push(box_)
+ }
+
+ pub(crate) fn append(&mut self, other: Self) {
+ vec_append_owned(
+ &mut self.for_initial_containing_block,
+ other.for_initial_containing_block,
+ );
+ match (
+ self.for_nearest_positioned_ancestor.as_mut(),
+ other.for_nearest_positioned_ancestor,
+ ) {
+ (Some(a), Some(b)) => vec_append_owned(a, b),
+ (None, None) => {},
+ _ => unreachable!(),
+ }
+ }
+
+ pub(crate) fn adjust_static_positions(
+ &mut self,
+ 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_nearest_so_far = self
+ .for_nearest_positioned_ancestor
+ .as_ref()
+ .map(|v| v.len());
+
+ let fragments = f(self);
+
+ adjust_static_positions(
+ &mut self.for_initial_containing_block[for_icb_so_far..],
+ &fragments,
+ tree_rank_in_parent,
+ );
+ if let Some(nearest) = &mut self.for_nearest_positioned_ancestor {
+ adjust_static_positions(
+ &mut nearest[for_nearest_so_far.unwrap()..],
+ &fragments,
+ tree_rank_in_parent,
+ );
+ }
+ fragments
+ }
+
+ pub(crate) fn layout_in_initial_containing_block(
+ &mut self,
+ layout_context: &LayoutContext,
+ initial_containing_block: &DefiniteContainingBlock,
+ fragments: &mut Vec<Fragment>,
) {
- if absolute.is_empty() {
- return;
+ debug_assert!(self.for_nearest_positioned_ancestor.is_none());
+
+ // 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() {
+ HoistedAbsolutelyPositionedBox::layout_many(
+ layout_context,
+ &std::mem::take(&mut self.for_initial_containing_block),
+ fragments,
+ &mut self.for_initial_containing_block,
+ initial_containing_block,
+ )
}
- let padding_rect = Rect {
- size: content_rect_size.clone(),
- // Ignore the content rect’s position in its own containing block:
- start_corner: Vec2::zero(),
+ }
+
+ fn layout_in_positioned_ancestor(
+ &mut self,
+ layout_context: &LayoutContext,
+ positioned_box_fragment: &mut BoxFragment,
+ ) {
+ let for_here = self.for_nearest_positioned_ancestor.take().unwrap();
+ if !for_here.is_empty() {
+ let padding_rect = Rect {
+ size: positioned_box_fragment.content_rect.size.clone(),
+ // Ignore the content rect’s position in its own containing block:
+ start_corner: Vec2::zero(),
+ }
+ .inflate(&positioned_box_fragment.padding);
+ let containing_block = DefiniteContainingBlock {
+ size: padding_rect.size.clone(),
+ style: &positioned_box_fragment.style,
+ };
+ let mut children = Vec::new();
+ HoistedAbsolutelyPositionedBox::layout_many(
+ layout_context,
+ &for_here,
+ &mut children,
+ &mut self.for_initial_containing_block,
+ &containing_block,
+ );
+ positioned_box_fragment
+ .children
+ .push(Fragment::Anonymous(AnonymousFragment {
+ children,
+ rect: padding_rect,
+ mode: positioned_box_fragment.style.writing_mode,
+ }))
}
- .inflate(&padding);
- let containing_block = DefiniteContainingBlock {
- size: padding_rect.size.clone(),
- style,
- };
- let map = |a: &AbsolutelyPositionedFragment| a.layout(layout_context, &containing_block);
- let children = if layout_context.use_rayon {
- absolute.par_iter().map(map).collect()
+ }
+}
+
+impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> {
+ pub(crate) fn layout_many(
+ layout_context: &LayoutContext,
+ boxes: &[Self],
+ fragments: &mut Vec<Fragment>,
+ for_initial_containing_block: &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_| {
+ Fragment::Box(box_.layout(
+ layout_context,
+ for_initial_containing_block,
+ containing_block,
+ ))
+ },
+ Vec::new,
+ vec_append_owned,
+ ))
} else {
- absolute.iter().map(map).collect()
- };
- fragments.push(Fragment::Anonymous(AnonymousFragment {
- children,
- rect: padding_rect,
- mode: style.writing_mode,
- }))
+ fragments.extend(boxes.iter().map(|box_| {
+ Fragment::Box(box_.layout(
+ layout_context,
+ for_initial_containing_block,
+ containing_block,
+ ))
+ }))
+ }
}
pub(crate) fn layout(
&self,
layout_context: &LayoutContext,
+ for_initial_containing_block: &mut Vec<HoistedAbsolutelyPositionedBox<'box_tree>>,
containing_block: &DefiniteContainingBlock,
- ) -> Fragment {
+ ) -> BoxFragment {
let style = &self.absolutely_positioned_box.contents.style;
let cbis = containing_block.size.inline;
let cbbs = containing_block.size.block;
@@ -216,95 +394,89 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
block_end: block_axis.margin_end,
};
- let mut absolutely_positioned_fragments = Vec::new();
- let (size, mut fragments) = match self.absolutely_positioned_box.contents.as_replaced() {
- Ok(replaced) => {
- // https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
- // https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
- let style = &self.absolutely_positioned_box.contents.style;
- let size = replaced_used_size.unwrap();
- let fragments = replaced.make_fragments(style, size.clone());
- (size, fragments)
- },
- Err(non_replaced) => {
- // https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width
- // https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-height
- let inline_size = inline_axis.size.auto_is(|| {
- let available_size = match inline_axis.anchor {
- Anchor::Start(start) => {
- cbis - start - pb.inline_sum() - margin.inline_sum()
- },
- Anchor::End(end) => cbis - end - pb.inline_sum() - margin.inline_sum(),
+ let for_icb = for_initial_containing_block;
+ PositioningContext::for_positioned(layout_context, for_icb, |positioning_context| {
+ let size;
+ let fragments;
+ match self.absolutely_positioned_box.contents.as_replaced() {
+ Ok(replaced) => {
+ // https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
+ // https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
+ let style = &self.absolutely_positioned_box.contents.style;
+ size = replaced_used_size.unwrap();
+ fragments = replaced.make_fragments(style, size.clone());
+ },
+ Err(non_replaced) => {
+ // https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width
+ // https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-height
+ let inline_size = inline_axis.size.auto_is(|| {
+ let available_size = match inline_axis.anchor {
+ Anchor::Start(start) => {
+ cbis - start - pb.inline_sum() - margin.inline_sum()
+ },
+ Anchor::End(end) => cbis - end - pb.inline_sum() - margin.inline_sum(),
+ };
+ self.absolutely_positioned_box
+ .contents
+ .content_sizes
+ .shrink_to_fit(available_size)
+ });
+
+ let containing_block_for_children = ContainingBlock {
+ inline_size,
+ block_size: block_axis.size,
+ style,
};
- self.absolutely_positioned_box
- .contents
- .content_sizes
- .shrink_to_fit(available_size)
- });
-
- let containing_block_for_children = ContainingBlock {
- inline_size,
- block_size: block_axis.size,
- style,
- };
- // https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
- assert_eq!(
- containing_block.style.writing_mode,
- containing_block_for_children.style.writing_mode,
- "Mixed writing modes are not supported yet"
- );
- let dummy_tree_rank = 0;
- let independent_layout = non_replaced.layout(
- layout_context,
- &containing_block_for_children,
- dummy_tree_rank,
- &mut absolutely_positioned_fragments,
- );
-
- let size = Vec2 {
- inline: inline_size,
- block: block_axis
- .size
- .auto_is(|| independent_layout.content_block_size),
- };
- (size, independent_layout.fragments)
- },
- };
+ // https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
+ assert_eq!(
+ containing_block.style.writing_mode,
+ containing_block_for_children.style.writing_mode,
+ "Mixed writing modes are not supported yet"
+ );
+ let dummy_tree_rank = 0;
+ let independent_layout = non_replaced.layout(
+ layout_context,
+ positioning_context,
+ &containing_block_for_children,
+ dummy_tree_rank,
+ );
- let inline_start = match inline_axis.anchor {
- Anchor::Start(start) => start + pb.inline_start + margin.inline_start,
- Anchor::End(end) => cbbs - 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,
- Anchor::End(end) => cbbs - end - pb.block_end - margin.block_end - size.block,
- };
+ size = Vec2 {
+ inline: inline_size,
+ block: block_axis
+ .size
+ .auto_is(|| independent_layout.content_block_size),
+ };
+ fragments = independent_layout.fragments
+ },
+ };
- let content_rect = Rect {
- start_corner: Vec2 {
- inline: inline_start,
- block: block_start,
- },
- size,
- };
+ 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,
+ };
+ let block_start = match block_axis.anchor {
+ Anchor::Start(start) => start + pb.block_start + margin.block_start,
+ Anchor::End(end) => cbbs - end - pb.block_end - margin.block_end - size.block,
+ };
- AbsolutelyPositionedFragment::in_positioned_containing_block(
- layout_context,
- &absolutely_positioned_fragments,
- &mut fragments,
- &content_rect.size,
- &padding,
- style,
- );
+ let content_rect = Rect {
+ start_corner: Vec2 {
+ inline: inline_start,
+ block: block_start,
+ },
+ size,
+ };
- Fragment::Box(BoxFragment {
- style: style.clone(),
- children: fragments,
- content_rect,
- padding,
- border,
- margin,
- block_margins_collapsed_with_children: CollapsedBlockMargins::zero(),
+ BoxFragment {
+ style: style.clone(),
+ children: fragments,
+ content_rect,
+ padding,
+ border,
+ margin,
+ block_margins_collapsed_with_children: CollapsedBlockMargins::zero(),
+ }
})
}
}
@@ -413,9 +585,9 @@ fn solve_axis(
}
}
-pub(crate) fn adjust_static_positions(
- absolutely_positioned_fragments: &mut [AbsolutelyPositionedFragment],
- child_fragments: &mut [Fragment],
+fn adjust_static_positions(
+ absolutely_positioned_fragments: &mut [HoistedAbsolutelyPositionedBox],
+ child_fragments: &[Fragment],
tree_rank_in_parent: usize,
) {
for abspos_fragment in absolutely_positioned_fragments {
@@ -436,3 +608,35 @@ pub(crate) fn adjust_static_positions(
}
}
}
+
+fn vec_append_owned<T>(a: &mut Vec<T>, mut b: Vec<T>) {
+ if a.is_empty() {
+ *a = b
+ } else {
+ a.append(&mut b)
+ }
+}
+
+/// https://drafts.csswg.org/css2/visuren.html#relative-positioning
+pub(crate) fn relative_adjustement(
+ style: &ComputedValues,
+ containing_block: &ContainingBlock,
+) -> Vec2<Length> {
+ let cbis = containing_block.inline_size;
+ let cbbs = containing_block.block_size.auto_is(Length::zero);
+ let box_offsets = style.box_offsets().map_inline_and_block_axes(
+ |v| v.percentage_relative_to(cbis),
+ |v| v.percentage_relative_to(cbbs),
+ );
+ fn adjust(start: LengthOrAuto, end: LengthOrAuto) -> Length {
+ match (start, end) {
+ (LengthOrAuto::Auto, LengthOrAuto::Auto) => Length::zero(),
+ (LengthOrAuto::Auto, LengthOrAuto::LengthPercentage(end)) => -end,
+ (LengthOrAuto::LengthPercentage(start), _) => start,
+ }
+ }
+ Vec2 {
+ inline: adjust(box_offsets.inline_start, box_offsets.inline_end),
+ block: adjust(box_offsets.block_start, box_offsets.block_end),
+ }
+}
diff --git a/components/style/properties/longhands/box.mako.rs b/components/style/properties/longhands/box.mako.rs
index b8b6cbc8c34..aa6118b8a8a 100644
--- a/components/style/properties/longhands/box.mako.rs
+++ b/components/style/properties/longhands/box.mako.rs
@@ -55,6 +55,9 @@ impl computed_value::T {
pub fn is_absolutely_positioned(self) -> bool {
matches!(self, Self::Absolute | Self::Fixed)
}
+ pub fn is_relative(self) -> bool {
+ self == Self::Relative
+ }
}
</%helpers:single_keyword>
diff --git a/components/style/properties/shorthands/background.mako.rs b/components/style/properties/shorthands/background.mako.rs
index 011ff5cb3d8..124d4fe406c 100644
--- a/components/style/properties/shorthands/background.mako.rs
+++ b/components/style/properties/shorthands/background.mako.rs
@@ -193,6 +193,29 @@
}
</%helpers:shorthand>
+<%helpers:shorthand name="background"
+ engines="servo-2020"
+ sub_properties="background-color"
+ spec="https://drafts.csswg.org/css-backgrounds/#the-background">
+ use crate::values::specified::Color;
+ use crate::parser::Parse;
+
+ pub fn parse_value<'i, 't>(
+ context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<Longhands, ParseError<'i>> {
+ Ok(expanded! {
+ background_color: Color::parse(context, input)?
+ })
+ }
+
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
+ self.background_color.to_css(dest)
+ }
+ }
+</%helpers:shorthand>
+
<%helpers:shorthand name="background-position"
engines="gecko servo-2013"
flags="SHORTHAND_IN_GETCS"
diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/block-in-inline-008.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/block-in-inline-008.xht.ini
deleted file mode 100644
index 5089f96e696..00000000000
--- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/block-in-inline-008.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[block-in-inline-008.xht]
- expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/block-in-inline-relpos-001.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/block-in-inline-relpos-001.xht.ini
deleted file mode 100644
index 36bc0e014bb..00000000000
--- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/block-in-inline-relpos-001.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[block-in-inline-relpos-001.xht]
- expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-001.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-001.xht.ini
deleted file mode 100644
index fe9734b830b..00000000000
--- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-001.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[containing-block-001.xht]
- expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-002.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-002.xht.ini
deleted file mode 100644
index e2c7dd3545b..00000000000
--- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-002.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[containing-block-002.xht]
- expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-003.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-003.xht.ini
deleted file mode 100644
index 245262f0b90..00000000000
--- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-003.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[containing-block-003.xht]
- expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-004.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-004.xht.ini
deleted file mode 100644
index 199c0c4dd37..00000000000
--- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-004.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[containing-block-004.xht]
- expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-005.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-005.xht.ini
deleted file mode 100644
index 612786df8b4..00000000000
--- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-005.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[containing-block-005.xht]
- expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-006.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-006.xht.ini
deleted file mode 100644
index 0394efb0d59..00000000000
--- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-006.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[containing-block-006.xht]
- expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-007.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-007.xht.ini
deleted file mode 100644
index 0c000bb2cd3..00000000000
--- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-007.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[containing-block-007.xht]
- expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-008.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-008.xht.ini
deleted file mode 100644
index dd630be0f54..00000000000
--- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-008.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[containing-block-008.xht]
- expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-010.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-010.xht.ini
deleted file mode 100644
index af40eef0a5d..00000000000
--- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-010.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[containing-block-010.xht]
- expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-023.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-023.xht.ini
new file mode 100644
index 00000000000..906c33cc7ca
--- /dev/null
+++ b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-023.xht.ini
@@ -0,0 +1,2 @@
+[containing-block-023.xht]
+ expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-026.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-026.xht.ini
deleted file mode 100644
index 46f865284ca..00000000000
--- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-026.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[containing-block-026.xht]
- expected: FAIL