mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Give PositioningContext
more responsibilities
Iits details are now private to the module. It has a couple methods that take closures to make sure that "before" and "after" steps are done together: * In an absolutely positioned box, take care of nested abspos (establish a new containing block, etc.) * For a box that *might* be `position: relative`, optionally take care of the same.
This commit is contained in:
parent
1c8d14ac0d
commit
c44ee516a1
4 changed files with 271 additions and 222 deletions
|
@ -245,7 +245,6 @@ impl InlineFormattingContext {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
ifc.positioning_context
|
ifc.positioning_context
|
||||||
.abspos
|
|
||||||
.push(box_.layout(initial_start_corner, tree_rank));
|
.push(box_.layout(initial_start_corner, tree_rank));
|
||||||
},
|
},
|
||||||
InlineLevelBox::OutOfFlowFloatBox(_box_) => {
|
InlineLevelBox::OutOfFlowFloatBox(_box_) => {
|
||||||
|
|
|
@ -18,7 +18,6 @@ use crate::{relative_adjustement, ContainingBlock};
|
||||||
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
||||||
use rayon_croissant::ParallelIteratorExt;
|
use rayon_croissant::ParallelIteratorExt;
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
use style::computed_values::position::T as Position;
|
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::values::computed::{Length, LengthOrAuto};
|
use style::values::computed::{Length, LengthOrAuto};
|
||||||
use style::Zero;
|
use style::Zero;
|
||||||
|
@ -235,8 +234,8 @@ fn layout_block_level_children<'a>(
|
||||||
/* float_context = */ None,
|
/* float_context = */ None,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
Default::default,
|
PositioningContext::new,
|
||||||
|left, right| left.append(right),
|
PositioningContext::append,
|
||||||
)
|
)
|
||||||
.collect();
|
.collect();
|
||||||
for fragment in &mut fragments {
|
for fragment in &mut fragments {
|
||||||
|
@ -317,9 +316,7 @@ impl BlockLevelBox {
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
|
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
|
||||||
positioning_context
|
positioning_context.push(box_.layout(Vec2::zero(), tree_rank));
|
||||||
.abspos
|
|
||||||
.push(box_.layout(Vec2::zero(), tree_rank));
|
|
||||||
Fragment::Anonymous(AnonymousFragment::no_op(
|
Fragment::Anonymous(AnonymousFragment::no_op(
|
||||||
containing_block.style.writing_mode,
|
containing_block.style.writing_mode,
|
||||||
))
|
))
|
||||||
|
@ -433,80 +430,70 @@ fn layout_in_flow_non_replaced_block_level<'a>(
|
||||||
min_box_size.block == Length::zero() &&
|
min_box_size.block == Length::zero() &&
|
||||||
pb.block_end == Length::zero() &&
|
pb.block_end == Length::zero() &&
|
||||||
block_level_kind == BlockLevelKind::SameFormattingContextBlock;
|
block_level_kind == BlockLevelKind::SameFormattingContextBlock;
|
||||||
let mut nested_positioning_context = PositioningContext { abspos: Vec::new() };
|
|
||||||
let mut flow_layout = layout_contents(
|
positioning_context.for_maybe_position_relative(layout_context, style, |positioning_context| {
|
||||||
if style.get_box().position == Position::Relative {
|
let mut flow_layout = layout_contents(
|
||||||
&mut nested_positioning_context
|
positioning_context,
|
||||||
} else {
|
&containing_block_for_children,
|
||||||
positioning_context
|
this_start_margin_can_collapse_with_children,
|
||||||
},
|
);
|
||||||
&containing_block_for_children,
|
let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
|
||||||
this_start_margin_can_collapse_with_children,
|
if this_start_margin_can_collapse_with_children.0 {
|
||||||
);
|
|
||||||
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
|
block_margins_collapsed_with_children
|
||||||
.start
|
.start
|
||||||
.adjoin_assign(&std::mem::replace(
|
.adjoin_assign(&flow_layout.collapsible_margins_in_children.start);
|
||||||
&mut flow_layout.collapsible_margins_in_children.end,
|
if flow_layout
|
||||||
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
|
.collapsible_margins_in_children
|
||||||
.collapsed_through;
|
.collapsed_through
|
||||||
let relative_adjustement = relative_adjustement(style, inline_size, block_size);
|
{
|
||||||
let block_size = block_size.auto_is(|| {
|
block_margins_collapsed_with_children
|
||||||
flow_layout
|
.start
|
||||||
.content_block_size
|
.adjoin_assign(&std::mem::replace(
|
||||||
.clamp_between_extremums(min_box_size.block, max_box_size.block)
|
&mut flow_layout.collapsible_margins_in_children.end,
|
||||||
});
|
CollapsedMargin::zero(),
|
||||||
let content_rect = Rect {
|
));
|
||||||
start_corner: Vec2 {
|
}
|
||||||
block: pb.block_start + relative_adjustement.block,
|
}
|
||||||
inline: pb.inline_start + relative_adjustement.inline + margin.inline_start,
|
if this_end_margin_can_collapse_with_children {
|
||||||
},
|
block_margins_collapsed_with_children
|
||||||
size: Vec2 {
|
.end
|
||||||
block: block_size,
|
.adjoin_assign(&flow_layout.collapsible_margins_in_children.end);
|
||||||
inline: inline_size,
|
} else {
|
||||||
},
|
flow_layout.content_block_size +=
|
||||||
};
|
flow_layout.collapsible_margins_in_children.end.solve();
|
||||||
if style.get_box().position == Position::Relative {
|
}
|
||||||
nested_positioning_context.layout_abspos(
|
block_margins_collapsed_with_children.collapsed_through =
|
||||||
layout_context,
|
this_start_margin_can_collapse_with_children.0 &&
|
||||||
&mut flow_layout.fragments,
|
this_end_margin_can_collapse_with_children &&
|
||||||
&content_rect.size,
|
flow_layout
|
||||||
&padding,
|
.collapsible_margins_in_children
|
||||||
style,
|
.collapsed_through;
|
||||||
)
|
let relative_adjustement = relative_adjustement(style, inline_size, block_size);
|
||||||
}
|
let block_size = block_size.auto_is(|| {
|
||||||
BoxFragment {
|
flow_layout
|
||||||
style: style.clone(),
|
.content_block_size
|
||||||
children: flow_layout.fragments,
|
.clamp_between_extremums(min_box_size.block, max_box_size.block)
|
||||||
content_rect,
|
});
|
||||||
padding,
|
let content_rect = Rect {
|
||||||
border,
|
start_corner: Vec2 {
|
||||||
margin,
|
block: pb.block_start + relative_adjustement.block,
|
||||||
block_margins_collapsed_with_children,
|
inline: pb.inline_start + relative_adjustement.inline + margin.inline_start,
|
||||||
}
|
},
|
||||||
|
size: Vec2 {
|
||||||
|
block: block_size,
|
||||||
|
inline: inline_size,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
BoxFragment {
|
||||||
|
style: style.clone(),
|
||||||
|
children: flow_layout.fragments,
|
||||||
|
content_rect,
|
||||||
|
padding,
|
||||||
|
border,
|
||||||
|
margin,
|
||||||
|
block_margins_collapsed_with_children,
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css2/visudet.html#block-replaced-width
|
/// https://drafts.csswg.org/css2/visudet.html#block-replaced-width
|
||||||
|
|
|
@ -12,13 +12,12 @@ use crate::formatting_contexts::IndependentFormattingContext;
|
||||||
use crate::fragments::Fragment;
|
use crate::fragments::Fragment;
|
||||||
use crate::geom;
|
use crate::geom;
|
||||||
use crate::geom::flow_relative::Vec2;
|
use crate::geom::flow_relative::Vec2;
|
||||||
|
use crate::positioned::AbsolutelyPositionedBox;
|
||||||
use crate::positioned::PositioningContext;
|
use crate::positioned::PositioningContext;
|
||||||
use crate::positioned::{AbsolutelyPositionedBox, CollectedAbsolutelyPositionedBox};
|
|
||||||
use crate::replaced::ReplacedContent;
|
use crate::replaced::ReplacedContent;
|
||||||
use crate::sizing::ContentSizesRequest;
|
use crate::sizing::ContentSizesRequest;
|
||||||
use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside};
|
use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside};
|
||||||
use crate::DefiniteContainingBlock;
|
use crate::DefiniteContainingBlock;
|
||||||
use rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator};
|
|
||||||
use script_layout_interface::wrapper_traits::LayoutNode;
|
use script_layout_interface::wrapper_traits::LayoutNode;
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
|
@ -111,7 +110,7 @@ impl BoxTreeRoot {
|
||||||
};
|
};
|
||||||
|
|
||||||
let dummy_tree_rank = 0;
|
let dummy_tree_rank = 0;
|
||||||
let mut positioning_context = PositioningContext { abspos: Vec::new() };
|
let mut positioning_context = PositioningContext::new();
|
||||||
let mut independent_layout = self.0.layout(
|
let mut independent_layout = self.0.layout(
|
||||||
layout_context,
|
layout_context,
|
||||||
&mut positioning_context,
|
&mut positioning_context,
|
||||||
|
@ -119,18 +118,11 @@ impl BoxTreeRoot {
|
||||||
dummy_tree_rank,
|
dummy_tree_rank,
|
||||||
);
|
);
|
||||||
|
|
||||||
let map = |a: &CollectedAbsolutelyPositionedBox| {
|
positioning_context.layout_in_initial_containing_block(
|
||||||
a.layout(layout_context, &initial_containing_block)
|
layout_context,
|
||||||
};
|
&initial_containing_block,
|
||||||
if layout_context.use_rayon {
|
&mut independent_layout.fragments,
|
||||||
independent_layout
|
);
|
||||||
.fragments
|
|
||||||
.par_extend(positioning_context.abspos.par_iter().map(map))
|
|
||||||
} else {
|
|
||||||
independent_layout
|
|
||||||
.fragments
|
|
||||||
.extend(positioning_context.abspos.iter().map(map))
|
|
||||||
}
|
|
||||||
|
|
||||||
FragmentTreeRoot(independent_layout.fragments)
|
FragmentTreeRoot(independent_layout.fragments)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,9 @@ use crate::geom::flow_relative::{Rect, Sides, Vec2};
|
||||||
use crate::sizing::ContentSizesRequest;
|
use crate::sizing::ContentSizesRequest;
|
||||||
use crate::style_ext::{ComputedValuesExt, DisplayInside};
|
use crate::style_ext::{ComputedValuesExt, DisplayInside};
|
||||||
use crate::{ContainingBlock, DefiniteContainingBlock};
|
use crate::{ContainingBlock, DefiniteContainingBlock};
|
||||||
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator};
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
|
use style::computed_values::position::T as Position;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
|
use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
|
||||||
use style::Zero;
|
use style::Zero;
|
||||||
|
@ -21,10 +22,8 @@ pub(crate) struct AbsolutelyPositionedBox {
|
||||||
pub contents: IndependentFormattingContext,
|
pub contents: IndependentFormattingContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub(crate) struct PositioningContext<'box_tree> {
|
pub(crate) struct PositioningContext<'box_tree> {
|
||||||
/// With `position: absolute`
|
boxes: Vec<CollectedAbsolutelyPositionedBox<'box_tree>>,
|
||||||
pub abspos: Vec<CollectedAbsolutelyPositionedBox<'box_tree>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -83,8 +82,8 @@ impl AbsolutelyPositionedBox {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn layout<'a>(
|
pub(crate) fn layout(
|
||||||
&'a self,
|
&self,
|
||||||
initial_start_corner: Vec2<Length>,
|
initial_start_corner: Vec2<Length>,
|
||||||
tree_rank: usize,
|
tree_rank: usize,
|
||||||
) -> CollectedAbsolutelyPositionedBox {
|
) -> CollectedAbsolutelyPositionedBox {
|
||||||
|
@ -123,73 +122,143 @@ impl AbsolutelyPositionedBox {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PositioningContext<'_> {
|
impl<'box_tree> PositioningContext<'box_tree> {
|
||||||
/// Unlike `Vec::append`, this takes ownership of the other value.
|
pub(crate) fn new() -> Self {
|
||||||
pub(crate) fn append(&mut self, mut other: Self) {
|
Self {
|
||||||
if self.abspos.is_empty() {
|
boxes: Vec::new(),
|
||||||
self.abspos = other.abspos
|
|
||||||
} else {
|
|
||||||
self.abspos.append(&mut other.abspos)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn for_maybe_position_relative(
|
||||||
|
&mut self,
|
||||||
|
layout_context: &LayoutContext,
|
||||||
|
style: &ComputedValues,
|
||||||
|
f: impl FnOnce(&mut Self) -> BoxFragment,
|
||||||
|
) -> BoxFragment {
|
||||||
|
if style.clone_position() == Position::Relative {
|
||||||
|
Self::for_positioned(layout_context, f)
|
||||||
|
} else {
|
||||||
|
f(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn for_positioned(
|
||||||
|
layout_context: &LayoutContext,
|
||||||
|
f: impl FnOnce(&mut Self) -> BoxFragment,
|
||||||
|
) -> BoxFragment {
|
||||||
|
let mut new = Self::new();
|
||||||
|
let mut positioned_box_fragment = f(&mut new);
|
||||||
|
new.layout_in_positioned_ancestor(layout_context, &mut positioned_box_fragment);
|
||||||
|
positioned_box_fragment
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn push(&mut self, box_: CollectedAbsolutelyPositionedBox<'box_tree>) {
|
||||||
|
self.boxes.push(box_)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn append(&mut self, other: Self) {
|
||||||
|
vec_append_owned(
|
||||||
|
&mut self.boxes,
|
||||||
|
other.boxes,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn adjust_static_positions(
|
pub(crate) fn adjust_static_positions(
|
||||||
&mut self,
|
&mut self,
|
||||||
tree_rank_in_parent: usize,
|
tree_rank_in_parent: usize,
|
||||||
f: impl FnOnce(&mut Self) -> Vec<Fragment>,
|
f: impl FnOnce(&mut Self) -> Vec<Fragment>,
|
||||||
) -> Vec<Fragment> {
|
) -> Vec<Fragment> {
|
||||||
let abspos_so_far = self.abspos.len();
|
let so_far = self.boxes.len();
|
||||||
|
|
||||||
let fragments = f(self);
|
let fragments = f(self);
|
||||||
|
|
||||||
adjust_static_positions(
|
adjust_static_positions(
|
||||||
&mut self.abspos[abspos_so_far..],
|
&mut self.boxes[so_far..],
|
||||||
&fragments,
|
&fragments,
|
||||||
tree_rank_in_parent,
|
tree_rank_in_parent,
|
||||||
);
|
);
|
||||||
fragments
|
fragments
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn layout_abspos(
|
pub(crate) fn layout_in_initial_containing_block(
|
||||||
self,
|
&mut self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
|
initial_containing_block: &DefiniteContainingBlock,
|
||||||
fragments: &mut Vec<Fragment>,
|
fragments: &mut Vec<Fragment>,
|
||||||
content_rect_size: &Vec2<Length>,
|
|
||||||
padding: &Sides<Length>,
|
|
||||||
style: &ComputedValues,
|
|
||||||
) {
|
) {
|
||||||
if self.abspos.is_empty() {
|
CollectedAbsolutelyPositionedBox::layout_many(
|
||||||
return;
|
layout_context,
|
||||||
|
&self.boxes,
|
||||||
|
fragments,
|
||||||
|
initial_containing_block,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layout_in_positioned_ancestor(
|
||||||
|
&mut self,
|
||||||
|
layout_context: &LayoutContext,
|
||||||
|
positioned_box_fragment: &mut BoxFragment,
|
||||||
|
) {
|
||||||
|
if !self.boxes.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();
|
||||||
|
CollectedAbsolutelyPositionedBox::layout_many(
|
||||||
|
layout_context,
|
||||||
|
&self.boxes,
|
||||||
|
&mut children,
|
||||||
|
&containing_block,
|
||||||
|
);
|
||||||
|
positioned_box_fragment
|
||||||
|
.children
|
||||||
|
.push(Fragment::Anonymous(AnonymousFragment {
|
||||||
|
children,
|
||||||
|
rect: padding_rect,
|
||||||
|
mode: positioned_box_fragment.style.writing_mode,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
let padding_rect = Rect {
|
|
||||||
size: content_rect_size.clone(),
|
|
||||||
// Ignore the content rect’s position in its own containing block:
|
|
||||||
start_corner: Vec2::zero(),
|
|
||||||
}
|
|
||||||
.inflate(&padding);
|
|
||||||
let containing_block = DefiniteContainingBlock {
|
|
||||||
size: padding_rect.size.clone(),
|
|
||||||
style,
|
|
||||||
};
|
|
||||||
let map =
|
|
||||||
|a: &CollectedAbsolutelyPositionedBox| a.layout(layout_context, &containing_block);
|
|
||||||
let children = if layout_context.use_rayon {
|
|
||||||
self.abspos.par_iter().map(map).collect()
|
|
||||||
} else {
|
|
||||||
self.abspos.iter().map(map).collect()
|
|
||||||
};
|
|
||||||
fragments.push(Fragment::Anonymous(AnonymousFragment {
|
|
||||||
children,
|
|
||||||
rect: padding_rect,
|
|
||||||
mode: style.writing_mode,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CollectedAbsolutelyPositionedBox<'_> {
|
impl<'box_tree> CollectedAbsolutelyPositionedBox<'box_tree> {
|
||||||
|
pub(crate) fn layout_many(
|
||||||
|
layout_context: &LayoutContext,
|
||||||
|
boxes: &[Self],
|
||||||
|
fragments: &mut Vec<Fragment>,
|
||||||
|
containing_block: &DefiniteContainingBlock,
|
||||||
|
) {
|
||||||
|
if layout_context.use_rayon {
|
||||||
|
fragments.par_extend(boxes.par_iter().map(
|
||||||
|
|box_| {
|
||||||
|
Fragment::Box(box_.layout(
|
||||||
|
layout_context,
|
||||||
|
containing_block,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
fragments.extend(boxes.iter().map(|box_| {
|
||||||
|
Fragment::Box(box_.layout(
|
||||||
|
layout_context,
|
||||||
|
containing_block,
|
||||||
|
))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn layout(
|
pub(crate) fn layout(
|
||||||
&self,
|
&self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
containing_block: &DefiniteContainingBlock,
|
containing_block: &DefiniteContainingBlock,
|
||||||
) -> Fragment {
|
) -> BoxFragment {
|
||||||
let style = &self.absolutely_positioned_box.contents.style;
|
let style = &self.absolutely_positioned_box.contents.style;
|
||||||
let cbis = containing_block.size.inline;
|
let cbis = containing_block.size.inline;
|
||||||
let cbbs = containing_block.size.block;
|
let cbbs = containing_block.size.block;
|
||||||
|
@ -249,94 +318,88 @@ impl CollectedAbsolutelyPositionedBox<'_> {
|
||||||
block_end: block_axis.margin_end,
|
block_end: block_axis.margin_end,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut positioning_context = PositioningContext { abspos: Vec::new() };
|
PositioningContext::for_positioned(layout_context, |positioning_context| {
|
||||||
let (size, mut fragments) = match self.absolutely_positioned_box.contents.as_replaced() {
|
let size;
|
||||||
Ok(replaced) => {
|
let fragments;
|
||||||
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
|
match self.absolutely_positioned_box.contents.as_replaced() {
|
||||||
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
|
Ok(replaced) => {
|
||||||
let style = &self.absolutely_positioned_box.contents.style;
|
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
|
||||||
let size = replaced_used_size.unwrap();
|
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
|
||||||
let fragments = replaced.make_fragments(style, size.clone());
|
let style = &self.absolutely_positioned_box.contents.style;
|
||||||
(size, fragments)
|
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
|
Err(non_replaced) => {
|
||||||
// https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-height
|
// https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width
|
||||||
let inline_size = inline_axis.size.auto_is(|| {
|
// https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-height
|
||||||
let available_size = match inline_axis.anchor {
|
let inline_size = inline_axis.size.auto_is(|| {
|
||||||
Anchor::Start(start) => {
|
let available_size = match inline_axis.anchor {
|
||||||
cbis - start - pb.inline_sum() - margin.inline_sum()
|
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
|
||||||
|
.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
|
// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
|
||||||
.contents
|
assert_eq!(
|
||||||
.content_sizes
|
containing_block.style.writing_mode,
|
||||||
.shrink_to_fit(available_size)
|
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 containing_block_for_children = ContainingBlock {
|
size = Vec2 {
|
||||||
inline_size,
|
inline: inline_size,
|
||||||
block_size: block_axis.size,
|
block: block_axis
|
||||||
style,
|
.size
|
||||||
};
|
.auto_is(|| independent_layout.content_block_size),
|
||||||
// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
|
};
|
||||||
assert_eq!(
|
fragments = independent_layout.fragments
|
||||||
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,
|
|
||||||
&mut positioning_context,
|
|
||||||
&containing_block_for_children,
|
|
||||||
dummy_tree_rank,
|
|
||||||
);
|
|
||||||
|
|
||||||
let size = Vec2 {
|
let inline_start = match inline_axis.anchor {
|
||||||
inline: inline_size,
|
Anchor::Start(start) => start + pb.inline_start + margin.inline_start,
|
||||||
block: block_axis
|
Anchor::End(end) => cbbs - end - pb.inline_end - margin.inline_end - size.inline,
|
||||||
.size
|
};
|
||||||
.auto_is(|| independent_layout.content_block_size),
|
let block_start = match block_axis.anchor {
|
||||||
};
|
Anchor::Start(start) => start + pb.block_start + margin.block_start,
|
||||||
(size, independent_layout.fragments)
|
Anchor::End(end) => cbbs - end - pb.block_end - margin.block_end - size.block,
|
||||||
},
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let inline_start = match inline_axis.anchor {
|
let content_rect = Rect {
|
||||||
Anchor::Start(start) => start + pb.inline_start + margin.inline_start,
|
start_corner: Vec2 {
|
||||||
Anchor::End(end) => cbbs - end - pb.inline_end - margin.inline_end - size.inline,
|
inline: inline_start,
|
||||||
};
|
block: block_start,
|
||||||
let block_start = match block_axis.anchor {
|
},
|
||||||
Anchor::Start(start) => start + pb.block_start + margin.block_start,
|
size,
|
||||||
Anchor::End(end) => cbbs - end - pb.block_end - margin.block_end - size.block,
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let content_rect = Rect {
|
BoxFragment {
|
||||||
start_corner: Vec2 {
|
style: style.clone(),
|
||||||
inline: inline_start,
|
children: fragments,
|
||||||
block: block_start,
|
content_rect,
|
||||||
},
|
padding,
|
||||||
size,
|
border,
|
||||||
};
|
margin,
|
||||||
|
block_margins_collapsed_with_children: CollapsedBlockMargins::zero(),
|
||||||
positioning_context.layout_abspos(
|
}
|
||||||
layout_context,
|
|
||||||
&mut fragments,
|
|
||||||
&content_rect.size,
|
|
||||||
&padding,
|
|
||||||
style,
|
|
||||||
);
|
|
||||||
|
|
||||||
Fragment::Box(BoxFragment {
|
|
||||||
style: style.clone(),
|
|
||||||
children: fragments,
|
|
||||||
content_rect,
|
|
||||||
padding,
|
|
||||||
border,
|
|
||||||
margin,
|
|
||||||
block_margins_collapsed_with_children: CollapsedBlockMargins::zero(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -468,3 +531,11 @@ 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue