Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement the `box-sizing` property #26079

Merged
merged 6 commits into from Apr 1, 2020
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -206,7 +206,7 @@ impl InlineFormattingContext {
}
}

fn add_lengthpercentage(&mut self, lp: LengthPercentage) {
fn add_lengthpercentage(&mut self, lp: &LengthPercentage) {
if let Some(l) = lp.to_length() {
self.add_length(l);
}
@@ -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,12 @@ 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 margin = pbm.margin.auto_is(Length::zero);
let pbm_sums = &(&pbm.padding + &pbm.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() {
@@ -550,51 +542,46 @@ fn layout_atomic(

let fragment = match atomic.as_replaced() {
Ok(replaced) => {
let size = replaced.used_size_as_if_inline_element(ifc.containing_block, &atomic.style);
let size =
replaced.used_size_as_if_inline_element(ifc.containing_block, &atomic.style, &pbm);
let fragments = replaced.make_fragments(&atomic.style, size.clone());
let content_rect = Rect { start_corner, size };
BoxFragment::new(
atomic.tag,
atomic.style.clone(),
fragments,
content_rect,
padding,
border,
pbm.padding,
pbm.border,
margin,
CollapsedBlockMargins::zero(),
)
},
Err(non_replaced) => {
let box_size = atomic.style.box_size();
let box_size = atomic.style.content_box_size(&ifc.containing_block, &pbm);
let max_box_size = atomic
.style
.max_box_size()
.percentages_relative_to(ifc.containing_block);
.content_max_box_size(&ifc.containing_block, &pbm);
let min_box_size = atomic
.style
.min_box_size()
.percentages_relative_to(ifc.containing_block)
.content_min_box_size(&ifc.containing_block, &pbm)
.auto_is(Length::zero);

// https://drafts.csswg.org/css2/visudet.html#inlineblock-width
let tentative_inline_size =
box_size.inline.percentage_relative_to(cbis).auto_is(|| {
let available_size = cbis - pbm.inline_sum();
atomic.content_sizes.shrink_to_fit(available_size)
});
let tentative_inline_size = box_size.inline.auto_is(|| {
let available_size = ifc.containing_block.inline_size - pbm_sums.inline_sum();
atomic.content_sizes.shrink_to_fit(available_size)
});

// https://drafts.csswg.org/css2/visudet.html#min-max-widths
// In this case “applying the rules above again” with a non-auto inline-size
// always results in that size.
let inline_size = tentative_inline_size
.clamp_between_extremums(min_box_size.inline, max_box_size.inline);

let block_size = box_size
.block
.maybe_percentage_relative_to(ifc.containing_block.block_size.non_auto());
let containing_block_for_children = ContainingBlock {
inline_size,
block_size,
block_size: box_size.block,
style: &atomic.style,
};
assert_eq!(
@@ -613,7 +600,9 @@ fn layout_atomic(
);

// https://drafts.csswg.org/css2/visudet.html#block-root-margin
let tentative_block_size = block_size.auto_is(|| independent_layout.content_block_size);
let tentative_block_size = box_size
.block
.auto_is(|| independent_layout.content_block_size);

// https://drafts.csswg.org/css2/visudet.html#min-max-heights
// In this case “applying the rules above again” with a non-auto block-size
@@ -633,18 +622,18 @@ fn layout_atomic(
atomic.style.clone(),
independent_layout.fragments,
content_rect,
padding,
border,
pbm.padding,
pbm.border,
margin,
CollapsedBlockMargins::zero(),
)
},
};

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));
@@ -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,40 +350,27 @@ 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 box_size = style.box_size().percentages_relative_to(containing_block);
let max_box_size = style
.max_box_size()
.percentages_relative_to(containing_block);
let pbm = style.padding_border_margin(containing_block);
let box_size = style.content_box_size(containing_block, &pbm);
let max_box_size = style.content_max_box_size(containing_block, &pbm);
let min_box_size = style
.min_box_size()
.percentages_relative_to(containing_block)
.content_min_box_size(containing_block, &pbm)
.auto_is(Length::zero);

// 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 +387,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 +414,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 +427,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,16 +446,16 @@ 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);
} 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 &&
start_margin_can_collapse_with_children &&
end_margin_can_collapse_with_children &&
collapsible_margins_in_children.collapsed_through;
},
NonReplacedContents::EstablishesAnIndependentFormattingContext(non_replaced) => {
@@ -485,8 +474,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 +487,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 +503,22 @@ fn layout_in_flow_replaced_block_level<'a>(
style: &Arc<ComputedValues>,
replaced: &ReplacedContent,
) -> BoxFragment {
let size = replaced.used_size_as_if_inline_element(containing_block, style);
let pbm = style.padding_border_margin(containing_block);
let size = replaced.used_size_as_if_inline_element(containing_block, style, &pbm);

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,24 +528,22 @@ 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,
)
}

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),
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.