Skip to content

Commit

Permalink
Implement the box-sizing property
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonSapin committed Mar 31, 2020
1 parent 0e35d70 commit c377d9c
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 94 deletions.
42 changes: 18 additions & 24 deletions components/layout_2020/flow/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,10 +529,8 @@ fn layout_atomic(
atomic: &IndependentFormattingContext,
) {
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;
let pbm_sums = &(&pbm.padding + &pbm.border) + &margin;
ifc.inline_position += pbm_sums.inline_start;
let mut start_corner = Vec2 {
block: pbm_sums.block_start,
Expand All @@ -544,52 +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 cbis = ifc.containing_block.inline_size;
let tentative_inline_size =
box_size.inline.percentage_relative_to(cbis).auto_is(|| {
let available_size = cbis - pbm_sums.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!(
Expand All @@ -608,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
Expand All @@ -628,8 +622,8 @@ fn layout_atomic(
atomic.style.clone(),
independent_layout.fragments,
content_rect,
padding,
border,
pbm.padding,
pbm.border,
margin,
CollapsedBlockMargins::zero(),
)
Expand Down
12 changes: 4 additions & 8 deletions components/layout_2020/flow/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,14 +351,10 @@ fn layout_in_flow_non_replaced_block_level(
float_context: Option<&mut FloatContext>,
) -> BoxFragment {
let pbm = style.padding_border_margin(containing_block);

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 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
Expand Down Expand Up @@ -508,7 +504,7 @@ fn layout_in_flow_replaced_block_level<'a>(
replaced: &ReplacedContent,
) -> BoxFragment {
let pbm = style.padding_border_margin(containing_block);
let size = replaced.used_size_as_if_inline_element(containing_block, style);
let size = replaced.used_size_as_if_inline_element(containing_block, style, &pbm);

let (margin_inline_start, margin_inline_end) =
solve_inline_margins_for_in_flow_block_level(containing_block, &pbm, size.inline);
Expand Down
15 changes: 6 additions & 9 deletions components/layout_2020/positioned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,19 +416,16 @@ impl HoistedAbsolutelyPositionedBox {
Ok(replaced) => {
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
let u = replaced.used_size_as_if_inline_element(&containing_block.into(), style);
let used_size =
replaced.used_size_as_if_inline_element(&containing_block.into(), style, &pbm);
size = Vec2 {
inline: LengthOrAuto::LengthPercentage(u.inline),
block: LengthOrAuto::LengthPercentage(u.block),
inline: LengthOrAuto::LengthPercentage(used_size.inline),
block: LengthOrAuto::LengthPercentage(used_size.block),
};
replaced_used_size = Some(u);
replaced_used_size = Some(used_size);
},
Err(_non_replaced) => {
let box_size = style.box_size();
size = Vec2 {
inline: box_size.inline.percentage_relative_to(cbis),
block: box_size.block.percentage_relative_to(cbbs),
};
size = style.content_box_size(&containing_block.into(), &pbm);
replaced_used_size = None;
},
}
Expand Down
12 changes: 5 additions & 7 deletions components/layout_2020/replaced.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::fragments::{DebugId, Fragment, ImageFragment};
use crate::geom::flow_relative::{Rect, Vec2};
use crate::geom::PhysicalSize;
use crate::sizing::ContentSizes;
use crate::style_ext::ComputedValuesExt;
use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin};
use crate::ContainingBlock;
use canvas_traits::canvas::{CanvasId, CanvasMsg, FromLayoutMsg};
use ipc_channel::ipc::{self, IpcSender};
Expand Down Expand Up @@ -240,19 +240,17 @@ impl ReplacedContent {
&self,
containing_block: &ContainingBlock,
style: &ComputedValues,
pbm: &PaddingBorderMargin,
) -> Vec2<Length> {
let mode = style.writing_mode;
let intrinsic_size = self.flow_relative_intrinsic_size(style);
let intrinsic_ratio = self.inline_size_over_block_size_intrinsic_ratio(style);

let box_size = style.box_size().percentages_relative_to(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);
let max_box_size = style
.max_box_size()
.percentages_relative_to(containing_block);

let default_object_size = || {
// FIXME:
Expand Down
91 changes: 53 additions & 38 deletions components/layout_2020/sizing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//! https://drafts.csswg.org/css-sizing/

use crate::style_ext::ComputedValuesExt;
use style::properties::longhands::box_sizing::computed_value::T as BoxSizing;
use style::properties::ComputedValues;
use style::values::computed::{Length, LengthPercentage, Percentage};
use style::values::generics::length::MaxSize;
Expand Down Expand Up @@ -63,6 +64,13 @@ impl ContentSizes {
}
}

fn map(&self, f: impl Fn(Length) -> Length) -> Self {
Self {
min_content: f(self.min_content),
max_content: f(self.max_content),
}
}

pub fn max_assign(&mut self, other: &Self) {
self.min_content.max_assign(other.min_content);
self.max_content.max_assign(other.max_content);
Expand Down Expand Up @@ -108,61 +116,68 @@ impl BoxContentSizes {
&self,
style: &ComputedValues,
) -> (ContentSizes, Percentage) {
// FIXME: account for 'box-sizing'
let inline_size = style.box_size().inline;
let padding = style.padding();
let border = style.border_width();
let margin = style.margin();

let mut pbm_percentages = Percentage::zero();
let mut decompose = |x: LengthPercentage| {
pbm_percentages += x.to_percentage().unwrap_or_else(Zero::zero);
x.to_length().unwrap_or_else(Zero::zero)
};
let pb_lengths =
border.inline_sum() + decompose(padding.inline_start) + decompose(padding.inline_end);
let mut m_lengths = Length::zero();
if let Some(m) = margin.inline_start.non_auto() {
m_lengths += decompose(m)
}
if let Some(m) = margin.inline_end.non_auto() {
m_lengths += decompose(m)
}

let box_sizing = style.get_position().box_sizing;
let inline_size = style
.box_size()
.inline
.non_auto()
// Percentages for 'width' are treated as 'auto'
.and_then(|lp| lp.to_length());
let min_inline_size = style
.min_box_size()
.inline
// Percentages for 'min-width' are treated as zero
.percentage_relative_to(Length::zero())
// FIXME: 'auto' is not zero in Flexbox
.auto_is(Length::zero);
let max_inline_size = match style.max_box_size().inline {
MaxSize::None => None,
// Percentages for 'max-width' are treated as 'none'
MaxSize::LengthPercentage(ref lp) => lp.to_length(),
};
let clamp = |l: Length| l.clamp_between_extremums(min_inline_size, max_inline_size);

// Percentages for 'width' are treated as 'auto'
let inline_size = inline_size.map(|lp| lp.to_length());
// The (inner) min/max-content are only used for 'auto'
let mut outer = match inline_size.non_auto().flatten() {
None => {
let inner = self.expect_inline().clone();
let border_box_sizes = match inline_size {
Some(non_auto) => {
let clamped = clamp(non_auto);
let border_box_size = match box_sizing {
BoxSizing::ContentBox => clamped + pb_lengths,
BoxSizing::BorderBox => clamped,
};
ContentSizes {
min_content: clamp(inner.min_content),
max_content: clamp(inner.max_content),
min_content: border_box_size,
max_content: border_box_size,
}
},
Some(length) => {
let length = clamp(length);
ContentSizes {
min_content: length,
max_content: length,
None => self.expect_inline().map(|content_box_size| {
match box_sizing {
// Clamp to 'min-width' and 'max-width', which are sizing the…
BoxSizing::ContentBox => clamp(content_box_size) + pb_lengths,
BoxSizing::BorderBox => clamp(content_box_size + pb_lengths),
}
},
}),
};

let mut pbm_lengths = Length::zero();
let mut pbm_percentages = Percentage::zero();
let padding = style.padding();
let border = style.border_width();
let margin = style.margin();
pbm_lengths += border.inline_sum();
let mut add = |x: LengthPercentage| {
if let Some(l) = x.to_length() {
pbm_lengths += l;
}
if let Some(p) = x.to_percentage() {
pbm_percentages += p;
}
};
add(padding.inline_start);
add(padding.inline_end);
margin.inline_start.non_auto().map(&mut add);
margin.inline_end.non_auto().map(&mut add);

outer.min_content += pbm_lengths;
outer.max_content += pbm_lengths;

let outer = border_box_sizes.map(|s| s + m_lengths);
(outer, pbm_percentages)
}

Expand Down
Loading

0 comments on commit c377d9c

Please sign in to comment.