Skip to content

Commit

Permalink
Add some helpers to resolve percentages of box sizes
Browse files Browse the repository at this point in the history
  • Loading branch information
nox committed Dec 4, 2019
1 parent 48ceb56 commit 4ebdc39
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 95 deletions.
176 changes: 81 additions & 95 deletions components/layout_2020/flow/mod.rs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIter
use rayon_croissant::ParallelIteratorExt; use rayon_croissant::ParallelIteratorExt;
use servo_arc::Arc; use servo_arc::Arc;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::{Length, LengthOrAuto}; use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
use style::values::generics::length::MaxSize; use style::values::generics::length::MaxSize;
use style::Zero; use style::Zero;


Expand Down Expand Up @@ -354,16 +354,16 @@ fn layout_in_flow_non_replaced_block_level<'a>(
) -> FlowLayout, ) -> FlowLayout,
) -> BoxFragment { ) -> BoxFragment {
let cbis = containing_block.inline_size; let cbis = containing_block.inline_size;
let cbbs = containing_block.block_size.non_auto();
let padding = style.padding().percentages_relative_to(cbis); let padding = style.padding().percentages_relative_to(cbis);
let border = style.border_width(); let border = style.border_width();
let margin = style.margin().percentages_relative_to(cbis); let margin = style.margin().percentages_relative_to(cbis);
let pb = &padding + &border; let pb = &padding + &border;
let pb_inline_sum = pb.inline_sum(); let pb_inline_sum = pb.inline_sum();


let box_size = style.box_size(); let box_size = percent_resolved_box_size(style.box_size(), containing_block);
let max_box_size = style.max_box_size(); let max_box_size = percent_resolved_max_box_size(style.max_box_size(), containing_block);
let min_box_size = style.min_box_size(); let min_box_size =
percent_resolved_box_size(style.min_box_size(), containing_block).auto_is(Length::zero);


// https://drafts.csswg.org/css2/visudet.html#min-max-widths // https://drafts.csswg.org/css2/visudet.html#min-max-widths
let solve_inline_margins = |inline_size| { let solve_inline_margins = |inline_size| {
Expand All @@ -376,7 +376,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
) )
}; };
let (mut inline_size, mut inline_margins) = let (mut inline_size, mut inline_margins) =
if let Some(inline_size) = box_size.inline.percentage_relative_to(cbis).non_auto() { if let Some(inline_size) = box_size.inline.non_auto() {
(inline_size, solve_inline_margins(inline_size)) (inline_size, solve_inline_margins(inline_size))
} else { } else {
let margin_inline_start = margin.inline_start.auto_is(Length::zero); let margin_inline_start = margin.inline_start.auto_is(Length::zero);
Expand All @@ -385,19 +385,14 @@ fn layout_in_flow_non_replaced_block_level<'a>(
let inline_size = cbis - pb_inline_sum - margin_inline_sum; let inline_size = cbis - pb_inline_sum - margin_inline_sum;
(inline_size, (margin_inline_start, margin_inline_end)) (inline_size, (margin_inline_start, margin_inline_end))
}; };
if let MaxSize::LengthPercentage(max_inline_size) = max_box_size.inline { if let Some(max_inline_size) = max_box_size.inline {
let max_inline_size = max_inline_size.percentage_relative_to(cbis);
if inline_size > max_inline_size { if inline_size > max_inline_size {
inline_size = max_inline_size; inline_size = max_inline_size;
inline_margins = solve_inline_margins(inline_size); inline_margins = solve_inline_margins(inline_size);
} }
} }
let min_inline_size = min_box_size if inline_size < min_box_size.inline {
.inline inline_size = min_box_size.inline;
.percentage_relative_to(cbis)
.auto_is(Length::zero);
if inline_size < min_inline_size {
inline_size = min_inline_size;
inline_margins = solve_inline_margins(inline_size); inline_margins = solve_inline_margins(inline_size);
} }


Expand All @@ -409,19 +404,9 @@ fn layout_in_flow_non_replaced_block_level<'a>(
}; };


// https://drafts.csswg.org/css2/visudet.html#min-max-heights // https://drafts.csswg.org/css2/visudet.html#min-max-heights
let max_block_size = match max_box_size.block { let mut block_size = box_size.block;
MaxSize::LengthPercentage(max_block_size) => {
max_block_size.maybe_percentage_relative_to(cbbs)
},
MaxSize::None => None,
};
let min_block_size = min_box_size
.block
.maybe_percentage_relative_to(cbbs)
.auto_is(Length::zero);
let mut block_size = box_size.block.maybe_percentage_relative_to(cbbs);
if let LengthOrAuto::LengthPercentage(ref mut block_size) = block_size { if let LengthOrAuto::LengthPercentage(ref mut block_size) = block_size {
*block_size = clamp_between_extremums(*block_size, min_block_size, max_block_size); *block_size = clamp_between_extremums(*block_size, min_box_size.block, max_box_size.block);
} }


let containing_block_for_children = ContainingBlock { let containing_block_for_children = ContainingBlock {
Expand All @@ -440,7 +425,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
pb.block_start == Length::zero(), pb.block_start == Length::zero(),
); );
let this_end_margin_can_collapse_with_children = block_size == LengthOrAuto::Auto && let this_end_margin_can_collapse_with_children = block_size == LengthOrAuto::Auto &&
min_block_size == 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_abspos = vec![]; let mut nested_abspos = vec![];
Expand Down Expand Up @@ -487,8 +472,8 @@ fn layout_in_flow_non_replaced_block_level<'a>(
let block_size = block_size.auto_is(|| { let block_size = block_size.auto_is(|| {
clamp_between_extremums( clamp_between_extremums(
flow_layout.content_block_size, flow_layout.content_block_size,
min_block_size, min_box_size.block,
max_block_size, max_box_size.block,
) )
}); });
let content_rect = Rect { let content_rect = Rect {
Expand Down Expand Up @@ -531,7 +516,6 @@ fn layout_in_flow_replaced_block_level<'a>(
replaced: &ReplacedContent, replaced: &ReplacedContent,
) -> BoxFragment { ) -> BoxFragment {
let cbis = containing_block.inline_size; let cbis = containing_block.inline_size;
let cbbs = containing_block.block_size.non_auto();
let padding = style.padding().percentages_relative_to(cbis); let padding = style.padding().percentages_relative_to(cbis);
let border = style.border_width(); let border = style.border_width();
let computed_margin = style.margin().percentages_relative_to(cbis); let computed_margin = style.margin().percentages_relative_to(cbis);
Expand All @@ -542,41 +526,20 @@ fn layout_in_flow_replaced_block_level<'a>(
// FIXME(nox): This can divide by zero. // FIXME(nox): This can divide by zero.
let intrinsic_ratio = intrinsic_size.inline.px() / intrinsic_size.block.px(); let intrinsic_ratio = intrinsic_size.inline.px() / intrinsic_size.block.px();


let box_size = style.box_size(); let box_size = percent_resolved_box_size(style.box_size(), containing_block);
let min_box_size = style.min_box_size(); let min_box_size =
let max_box_size = style.max_box_size(); percent_resolved_box_size(style.min_box_size(), containing_block).auto_is(Length::zero);

let max_box_size = percent_resolved_max_box_size(style.max_box_size(), containing_block);
let inline_size = box_size.inline.percentage_relative_to(cbis);
let min_inline_size = min_box_size
.inline
.percentage_relative_to(cbis)
.auto_is(Length::zero);
let max_inline_size = match max_box_size.inline {
MaxSize::LengthPercentage(max_inline_size) => {
Some(max_inline_size.percentage_relative_to(cbis))
},
MaxSize::None => None,
};
let block_size = box_size.block.maybe_percentage_relative_to(cbbs);
let min_block_size = min_box_size
.block
.maybe_percentage_relative_to(cbbs)
.auto_is(Length::zero);
let max_block_size = match max_box_size.block {
MaxSize::LengthPercentage(max_block_size) => {
max_block_size.maybe_percentage_relative_to(cbbs)
},
MaxSize::None => None,
};
let clamp = |inline_size, block_size| { let clamp = |inline_size, block_size| {
( (
clamp_between_extremums(inline_size, min_inline_size, max_inline_size), clamp_between_extremums(inline_size, min_box_size.inline, max_box_size.inline),
clamp_between_extremums(block_size, min_block_size, max_block_size), clamp_between_extremums(block_size, min_box_size.block, max_box_size.block),
) )
}; };
// https://drafts.csswg.org/css2/visudet.html#min-max-widths // https://drafts.csswg.org/css2/visudet.html#min-max-widths
// https://drafts.csswg.org/css2/visudet.html#min-max-heights // https://drafts.csswg.org/css2/visudet.html#min-max-heights
let (inline_size, block_size) = match (inline_size, block_size) { let (inline_size, block_size) = match (box_size.inline, box_size.block) {
(LengthOrAuto::LengthPercentage(inline), LengthOrAuto::LengthPercentage(block)) => { (LengthOrAuto::LengthPercentage(inline), LengthOrAuto::LengthPercentage(block)) => {
clamp(inline, block) clamp(inline, block)
}, },
Expand Down Expand Up @@ -605,39 +568,35 @@ fn layout_in_flow_replaced_block_level<'a>(
} }
}; };
match ( match (
violation(intrinsic_size.inline, min_inline_size, max_inline_size), violation(
violation(intrinsic_size.block, min_block_size, max_block_size), intrinsic_size.inline,
min_box_size.inline,
max_box_size.inline,
),
violation(intrinsic_size.block, min_box_size.block, max_box_size.block),
) { ) {
// Row 1. // Row 1.
(Violation::None, Violation::None) => (intrinsic_size.inline, intrinsic_size.block), (Violation::None, Violation::None) => (intrinsic_size.inline, intrinsic_size.block),
// Row 2. // Row 2.
(Violation::Above(max_inline_size), Violation::None) => { (Violation::Above(max_inline_size), Violation::None) => {
let block_size = (max_inline_size / intrinsic_ratio).max(min_block_size); let block_size = (max_inline_size / intrinsic_ratio).max(min_box_size.block);
(max_inline_size, block_size) (max_inline_size, block_size)
}, },
// Row 3. // Row 3.
(Violation::Below(min_inline_size), Violation::None) => { (Violation::Below(min_inline_size), Violation::None) => {
let mut block_size = min_inline_size / intrinsic_ratio; let block_size =
if let Some(max_block_size) = max_block_size { clamp_below_max(min_inline_size / intrinsic_ratio, max_box_size.block);
if block_size > max_block_size {
block_size = max_block_size;
}
}
(min_inline_size, block_size) (min_inline_size, block_size)
}, },
// Row 4. // Row 4.
(Violation::None, Violation::Above(max_block_size)) => { (Violation::None, Violation::Above(max_block_size)) => {
let inline_size = (max_block_size * intrinsic_ratio).max(min_inline_size); let inline_size = (max_block_size * intrinsic_ratio).max(min_box_size.inline);
(inline_size, max_block_size) (inline_size, max_block_size)
}, },
// Row 5. // Row 5.
(Violation::None, Violation::Below(min_block_size)) => { (Violation::None, Violation::Below(min_block_size)) => {
let mut inline_size = min_block_size * intrinsic_ratio; let inline_size =
if let Some(max_inline_size) = max_inline_size { clamp_below_max(min_block_size * intrinsic_ratio, max_box_size.inline);
if inline_size > max_inline_size {
inline_size = max_inline_size;
}
}
(inline_size, min_block_size) (inline_size, min_block_size)
}, },
// Rows 6-7. // Rows 6-7.
Expand All @@ -646,11 +605,13 @@ fn layout_in_flow_replaced_block_level<'a>(
max_block_size.px() / intrinsic_size.block.px() max_block_size.px() / intrinsic_size.block.px()
{ {
// Row 6. // Row 6.
let block_size = (max_inline_size / intrinsic_ratio).max(min_block_size); let block_size =
(max_inline_size / intrinsic_ratio).max(min_box_size.block);
(max_inline_size, block_size) (max_inline_size, block_size)
} else { } else {
// Row 7. // Row 7.
let inline_size = (max_block_size * intrinsic_ratio).max(min_inline_size); let inline_size =
(max_block_size * intrinsic_ratio).max(min_box_size.inline);
(inline_size, max_block_size) (inline_size, max_block_size)
} }
}, },
Expand All @@ -660,21 +621,13 @@ fn layout_in_flow_replaced_block_level<'a>(
min_block_size.px() / intrinsic_size.block.px() min_block_size.px() / intrinsic_size.block.px()
{ {
// Row 8. // Row 8.
let mut inline_size = min_block_size * intrinsic_ratio; let inline_size =
if let Some(max_inline_size) = max_inline_size { clamp_below_max(min_block_size * intrinsic_ratio, max_box_size.inline);
if inline_size > max_inline_size {
inline_size = max_inline_size;
}
}
(inline_size, min_block_size) (inline_size, min_block_size)
} else { } else {
// Row 9. // Row 9.
let mut block_size = min_inline_size / intrinsic_ratio; let block_size =
if let Some(max_block_size) = max_block_size { clamp_below_max(min_inline_size / intrinsic_ratio, max_box_size.block);
if block_size > max_block_size {
block_size = max_block_size;
}
}
(min_inline_size, block_size) (min_inline_size, block_size)
} }
}, },
Expand Down Expand Up @@ -755,11 +708,44 @@ fn solve_inline_margins_for_in_flow_block_level(
} }
} }


fn clamp_between_extremums(mut size: Length, min_size: Length, max_size: Option<Length>) -> Length { fn clamp_between_extremums(size: Length, min_size: Length, max_size: Option<Length>) -> Length {
if let Some(max_size) = max_size { clamp_below_max(size, max_size).max(min_size)
if size > max_size { }
size = max_size;
} fn clamp_below_max(size: Length, max_size: Option<Length>) -> Length {
max_size.map_or(size, |max_size| size.min(max_size))
}

fn percent_resolved_box_size(
box_size: Vec2<LengthPercentageOrAuto>,
containing_block: &ContainingBlock,
) -> Vec2<LengthOrAuto> {
Vec2 {
inline: box_size
.inline
.percentage_relative_to(containing_block.inline_size),
block: box_size
.block
.maybe_percentage_relative_to(containing_block.block_size.non_auto()),
}
}

fn percent_resolved_max_box_size(
max_box_size: Vec2<MaxSize<LengthPercentage>>,
containing_block: &ContainingBlock,
) -> Vec2<Option<Length>> {
Vec2 {
inline: match max_box_size.inline {
MaxSize::LengthPercentage(max_inline_size) => {
Some(max_inline_size.percentage_relative_to(containing_block.inline_size))
},
MaxSize::None => None,
},
block: match max_box_size.block {
MaxSize::LengthPercentage(max_block_size) => {
max_block_size.maybe_percentage_relative_to(containing_block.block_size.non_auto())
},
MaxSize::None => None,
},
} }
size.max(min_size)
} }
9 changes: 9 additions & 0 deletions components/layout_2020/geom.rs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -141,6 +141,15 @@ impl flow_relative::Vec2<Length> {
} }
} }


impl flow_relative::Vec2<LengthOrAuto> {
pub fn auto_is(&self, f: impl Fn() -> Length) -> flow_relative::Vec2<Length> {
flow_relative::Vec2 {
inline: self.inline.auto_is(&f),
block: self.block.auto_is(&f),
}
}
}

impl flow_relative::Rect<Length> { impl flow_relative::Rect<Length> {
pub fn zero() -> Self { pub fn zero() -> Self {
Self { Self {
Expand Down

0 comments on commit 4ebdc39

Please sign in to comment.