Introduce a PaddingBorderMargin helper

This commit is contained in:
Simon Sapin 2020-03-31 17:33:37 +02:00
parent 5f75f7ffdd
commit 0e35d70ca8
4 changed files with 101 additions and 102 deletions

View file

@ -421,13 +421,11 @@ impl InlineBox {
ifc: &mut InlineFormattingContextState<'box_tree, '_, '_>,
) -> PartialInlineBoxFragment<'box_tree> {
let style = self.style.clone();
let cbis = ifc.containing_block.inline_size;
let mut padding = style.padding().percentages_relative_to(cbis);
let mut border = style.border_width();
let mut margin = style
.margin()
.percentages_relative_to(cbis)
.auto_is(Length::zero);
let pbm = style.padding_border_margin(&ifc.containing_block);
let mut padding = pbm.padding;
let mut border = pbm.border;
let mut margin = pbm.margin.auto_is(Length::zero);
if self.first_fragment {
ifc.inline_position += padding.inline_start + border.inline_start + margin.inline_start;
} else {
@ -530,18 +528,14 @@ fn layout_atomic(
ifc: &mut InlineFormattingContextState,
atomic: &IndependentFormattingContext,
) {
let cbis = ifc.containing_block.inline_size;
let padding = atomic.style.padding().percentages_relative_to(cbis);
let border = atomic.style.border_width();
let margin = atomic
.style
.margin()
.percentages_relative_to(cbis)
.auto_is(Length::zero);
let pbm = &(&padding + &border) + &margin;
ifc.inline_position += pbm.inline_start;
let pbm = atomic.style.padding_border_margin(&ifc.containing_block);
let padding = pbm.padding;
let border = pbm.border;
let margin = pbm.margin.auto_is(Length::zero);
let pbm_sums = &(&padding + &border) + &margin;
ifc.inline_position += pbm_sums.inline_start;
let mut start_corner = Vec2 {
block: pbm.block_start,
block: pbm_sums.block_start,
inline: ifc.inline_position - ifc.current_nesting_level.inline_start,
};
if atomic.style.clone_position().is_relative() {
@ -577,9 +571,10 @@ fn layout_atomic(
.auto_is(Length::zero);
// https://drafts.csswg.org/css2/visudet.html#inlineblock-width
let cbis = ifc.containing_block.inline_size;
let tentative_inline_size =
box_size.inline.percentage_relative_to(cbis).auto_is(|| {
let available_size = cbis - pbm.inline_sum();
let available_size = cbis - pbm_sums.inline_sum();
atomic.content_sizes.shrink_to_fit(available_size)
});
@ -641,10 +636,10 @@ fn layout_atomic(
},
};
ifc.inline_position += pbm.inline_end + fragment.content_rect.size.inline;
ifc.inline_position += pbm_sums.inline_end + fragment.content_rect.size.inline;
ifc.current_nesting_level
.max_block_size_of_fragments_so_far
.max_assign(pbm.block_sum() + fragment.content_rect.size.block);
.max_assign(pbm_sums.block_sum() + fragment.content_rect.size.block);
ifc.current_nesting_level
.fragments_so_far
.push(Fragment::Box(fragment));

View file

@ -14,7 +14,7 @@ use crate::fragments::{CollapsedBlockMargins, CollapsedMargin, Fragment};
use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
use crate::replaced::ReplacedContent;
use crate::style_ext::ComputedValuesExt;
use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin};
use crate::ContainingBlock;
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
use rayon_croissant::ParallelIteratorExt;
@ -350,12 +350,7 @@ fn layout_in_flow_non_replaced_block_level(
tree_rank: usize,
float_context: Option<&mut FloatContext>,
) -> BoxFragment {
let cbis = containing_block.inline_size;
let padding = style.padding().percentages_relative_to(cbis);
let border = style.border_width();
let margin = style.margin().percentages_relative_to(cbis);
let pb = &padding + &border;
let pb_inline_sum = pb.inline_sum();
let pbm = style.padding_border_margin(containing_block);
let box_size = style.box_size().percentages_relative_to(containing_block);
let max_box_size = style
@ -368,22 +363,18 @@ fn layout_in_flow_non_replaced_block_level(
// https://drafts.csswg.org/css2/visudet.html#min-max-widths
let solve_inline_margins = |inline_size| {
solve_inline_margins_for_in_flow_block_level(
containing_block,
pb_inline_sum,
margin.inline_start,
margin.inline_end,
inline_size,
)
solve_inline_margins_for_in_flow_block_level(containing_block, &pbm, inline_size)
};
let (mut inline_size, mut inline_margins) =
if let Some(inline_size) = box_size.inline.non_auto() {
(inline_size, solve_inline_margins(inline_size))
} else {
let margin_inline_start = margin.inline_start.auto_is(Length::zero);
let margin_inline_end = margin.inline_end.auto_is(Length::zero);
let margin_inline_sum = margin_inline_start + margin_inline_end;
let inline_size = cbis - pb_inline_sum - margin_inline_sum;
let margin_inline_start = pbm.margin.inline_start.auto_is(Length::zero);
let margin_inline_end = pbm.margin.inline_end.auto_is(Length::zero);
let inline_size = containing_block.inline_size -
pbm.padding_border_sums.inline -
margin_inline_start -
margin_inline_end;
(inline_size, (margin_inline_start, margin_inline_end))
};
if let Some(max_inline_size) = max_box_size.inline {
@ -400,8 +391,8 @@ fn layout_in_flow_non_replaced_block_level(
let margin = Sides {
inline_start: inline_margins.0,
inline_end: inline_margins.1,
block_start: margin.block_start.auto_is(Length::zero),
block_end: margin.block_end.auto_is(Length::zero),
block_start: pbm.margin.block_start.auto_is(Length::zero),
block_end: pbm.margin.block_end.auto_is(Length::zero),
};
// https://drafts.csswg.org/css2/visudet.html#min-max-heights
@ -427,8 +418,10 @@ fn layout_in_flow_non_replaced_block_level(
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() &&
let start_margin_can_collapse_with_children = pbm.padding.block_start == Length::zero() &&
pbm.border.block_start == Length::zero();
let end_margin_can_collapse_with_children = pbm.padding.block_end == Length::zero() &&
pbm.border.block_end == Length::zero() &&
block_size == LengthOrAuto::Auto &&
min_box_size.block == Length::zero();
@ -438,13 +431,13 @@ fn layout_in_flow_non_replaced_block_level(
&containing_block_for_children,
tree_rank,
float_context,
CollapsibleWithParentStartMargin(this_start_margin_can_collapse_with_children),
CollapsibleWithParentStartMargin(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 {
if start_margin_can_collapse_with_children {
block_margins_collapsed_with_children
.start
.adjoin_assign(&collapsible_margins_in_children.start);
@ -457,7 +450,7 @@ fn layout_in_flow_non_replaced_block_level(
));
}
}
if this_end_margin_can_collapse_with_children {
if end_margin_can_collapse_with_children {
block_margins_collapsed_with_children
.end
.adjoin_assign(&collapsible_margins_in_children.end);
@ -465,8 +458,8 @@ fn layout_in_flow_non_replaced_block_level(
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 &&
start_margin_can_collapse_with_children &&
end_margin_can_collapse_with_children &&
collapsible_margins_in_children.collapsed_through;
},
NonReplacedContents::EstablishesAnIndependentFormattingContext(non_replaced) => {
@ -485,8 +478,8 @@ fn layout_in_flow_non_replaced_block_level(
});
let content_rect = Rect {
start_corner: Vec2 {
block: pb.block_start,
inline: pb.inline_start + margin.inline_start,
block: pbm.padding.block_start + pbm.border.block_start,
inline: pbm.padding.inline_start + pbm.border.inline_start + margin.inline_start,
},
size: Vec2 {
block: block_size,
@ -498,8 +491,8 @@ fn layout_in_flow_non_replaced_block_level(
style.clone(),
fragments,
content_rect,
padding,
border,
pbm.padding,
pbm.border,
margin,
block_margins_collapsed_with_children,
)
@ -514,32 +507,22 @@ fn layout_in_flow_replaced_block_level<'a>(
style: &Arc<ComputedValues>,
replaced: &ReplacedContent,
) -> BoxFragment {
let pbm = style.padding_border_margin(containing_block);
let size = replaced.used_size_as_if_inline_element(containing_block, style);
let cbis = containing_block.inline_size;
let padding = style.padding().percentages_relative_to(cbis);
let border = style.border_width();
let computed_margin = style.margin().percentages_relative_to(cbis);
let pb = &padding + &border;
let (margin_inline_start, margin_inline_end) = solve_inline_margins_for_in_flow_block_level(
containing_block,
pb.inline_sum(),
computed_margin.inline_start,
computed_margin.inline_end,
size.inline,
);
let (margin_inline_start, margin_inline_end) =
solve_inline_margins_for_in_flow_block_level(containing_block, &pbm, size.inline);
let margin = Sides {
inline_start: margin_inline_start,
inline_end: margin_inline_end,
block_start: computed_margin.block_start.auto_is(Length::zero),
block_end: computed_margin.block_end.auto_is(Length::zero),
block_start: pbm.margin.block_start.auto_is(Length::zero),
block_end: pbm.margin.block_end.auto_is(Length::zero),
};
let fragments = replaced.make_fragments(style, size.clone());
let content_rect = Rect {
start_corner: Vec2 {
block: pb.block_start,
inline: pb.inline_start + margin.inline_start,
block: pbm.padding.block_start + pbm.border.block_start,
inline: pbm.padding.inline_start + pbm.border.inline_start + margin.inline_start,
},
size,
};
@ -549,8 +532,8 @@ fn layout_in_flow_replaced_block_level<'a>(
style.clone(),
fragments,
content_rect,
padding,
border,
pbm.padding,
pbm.border,
margin,
block_margins_collapsed_with_children,
)
@ -558,15 +541,13 @@ fn layout_in_flow_replaced_block_level<'a>(
fn solve_inline_margins_for_in_flow_block_level(
containing_block: &ContainingBlock,
padding_border_inline_sum: Length,
computed_margin_inline_start: LengthOrAuto,
computed_margin_inline_end: LengthOrAuto,
pbm: &PaddingBorderMargin,
inline_size: Length,
) -> (Length, Length) {
let inline_margins = containing_block.inline_size - padding_border_inline_sum - inline_size;
match (computed_margin_inline_start, computed_margin_inline_end) {
(LengthOrAuto::Auto, LengthOrAuto::Auto) => (inline_margins / 2., inline_margins / 2.),
(LengthOrAuto::Auto, LengthOrAuto::LengthPercentage(end)) => (inline_margins - end, end),
(LengthOrAuto::LengthPercentage(start), _) => (start, inline_margins - start),
let available = containing_block.inline_size - pbm.padding_border_sums.inline - inline_size;
match (pbm.margin.inline_start, pbm.margin.inline_end) {
(LengthOrAuto::Auto, LengthOrAuto::Auto) => (available / 2., available / 2.),
(LengthOrAuto::Auto, LengthOrAuto::LengthPercentage(end)) => (available - end, end),
(LengthOrAuto::LengthPercentage(start), _) => (start, available - start),
}
}

View file

@ -405,9 +405,10 @@ impl HoistedAbsolutelyPositionedBox {
for_nearest_containing_block_for_all_descendants: &mut Vec<HoistedAbsolutelyPositionedBox>,
containing_block: &DefiniteContainingBlock,
) -> BoxFragment {
let style = &self.absolutely_positioned_box.contents.style;
let cbis = containing_block.size.inline;
let cbbs = containing_block.size.block;
let style = &self.absolutely_positioned_box.contents.style;
let pbm = style.padding_border_margin(&containing_block.into());
let size;
let replaced_used_size;
@ -432,16 +433,11 @@ impl HoistedAbsolutelyPositionedBox {
},
}
let padding = style.padding().percentages_relative_to(cbis);
let border = style.border_width();
let computed_margin = style.margin().percentages_relative_to(cbis);
let pb = &padding + &border;
let inline_axis = solve_axis(
cbis,
pb.inline_sum(),
computed_margin.inline_start.clone(),
computed_margin.inline_end.clone(),
pbm.padding_border_sums.inline,
pbm.margin.inline_start,
pbm.margin.inline_end,
/* avoid_negative_margin_start */ true,
self.box_offsets.inline.clone(),
size.inline,
@ -449,9 +445,9 @@ impl HoistedAbsolutelyPositionedBox {
let block_axis = solve_axis(
cbis,
pb.block_sum(),
computed_margin.block_start.clone(),
computed_margin.block_end.clone(),
pbm.padding_border_sums.block,
pbm.margin.block_start,
pbm.margin.block_end,
/* avoid_negative_margin_start */ false,
self.box_offsets.block.clone(),
size.block,
@ -483,14 +479,14 @@ impl HoistedAbsolutelyPositionedBox {
// 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 anchor = match inline_axis.anchor {
Anchor::Start(start) => start,
Anchor::End(end) => end,
};
let available_size = cbis -
anchor -
pbm.padding_border_sums.inline -
margin.inline_sum();
self.absolutely_positioned_box
.contents
.content_sizes
@ -526,6 +522,7 @@ impl HoistedAbsolutelyPositionedBox {
},
};
let pb = &pbm.padding + &pbm.border;
let inline_start = match inline_axis.anchor {
Anchor::Start(start) => start + pb.inline_start + margin.inline_start,
Anchor::End(end) => {
@ -550,8 +547,8 @@ impl HoistedAbsolutelyPositionedBox {
style.clone(),
fragments,
content_rect,
padding,
border,
pbm.padding,
pbm.border,
margin,
CollapsedBlockMargins::zero(),
)

View file

@ -3,11 +3,12 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::geom::{flow_relative, PhysicalSides, PhysicalSize};
use crate::ContainingBlock;
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::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
use style::values::computed::{NonNegativeLengthPercentage, Size};
use style::values::generics::box_::Perspective;
use style::values::generics::length::MaxSize;
@ -43,6 +44,16 @@ pub(crate) enum DisplayInside {
FlowRoot,
}
/// Percentages resolved but not `auto` margins
pub(crate) struct PaddingBorderMargin {
pub padding: flow_relative::Sides<Length>,
pub border: flow_relative::Sides<Length>,
pub margin: flow_relative::Sides<LengthOrAuto>,
/// Pre-computed sums in each axis
pub padding_border_sums: flow_relative::Vec2<Length>,
}
pub(crate) trait ComputedValuesExt {
fn inline_size_is_length(&self) -> bool;
fn inline_box_offsets_are_both_non_auto(&self) -> bool;
@ -50,6 +61,7 @@ pub(crate) trait ComputedValuesExt {
fn box_size(&self) -> flow_relative::Vec2<LengthPercentageOrAuto>;
fn min_box_size(&self) -> flow_relative::Vec2<LengthPercentageOrAuto>;
fn max_box_size(&self) -> flow_relative::Vec2<MaxSize<LengthPercentage>>;
fn padding_border_margin(&self, containing_block: &ContainingBlock) -> PaddingBorderMargin;
fn padding(&self) -> flow_relative::Sides<LengthPercentage>;
fn border_width(&self) -> flow_relative::Sides<Length>;
fn margin(&self) -> flow_relative::Sides<LengthPercentageOrAuto>;
@ -135,7 +147,21 @@ impl ComputedValuesExt for ComputedValues {
)
}
#[inline]
fn padding_border_margin(&self, containing_block: &ContainingBlock) -> PaddingBorderMargin {
let cbis = containing_block.inline_size;
let padding = self.padding().percentages_relative_to(cbis);
let border = self.border_width();
PaddingBorderMargin {
padding_border_sums: flow_relative::Vec2 {
inline: padding.inline_sum() + border.inline_sum(),
block: padding.block_sum() + border.block_sum(),
},
padding,
border,
margin: self.margin().percentages_relative_to(cbis),
}
}
fn padding(&self) -> flow_relative::Sides<LengthPercentage> {
let padding = self.get_padding();
flow_relative::Sides::from_physical(