aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout_2020
diff options
context:
space:
mode:
authorAnthony Ramine <nox@nox.paris>2019-12-04 17:05:04 +0100
committerAnthony Ramine <nox@nox.paris>2019-12-04 17:24:45 +0100
commit4ebdc39ecd94de69f6aebc528252b9b510381bd4 (patch)
tree9366a91bed79bf46ddef9b015f917b01c41bdaa6 /components/layout_2020
parent48ceb563395aa7dc8ae0e44d41296212d4126803 (diff)
downloadservo-4ebdc39ecd94de69f6aebc528252b9b510381bd4.tar.gz
servo-4ebdc39ecd94de69f6aebc528252b9b510381bd4.zip
Add some helpers to resolve percentages of box sizes
Diffstat (limited to 'components/layout_2020')
-rw-r--r--components/layout_2020/flow/mod.rs176
-rw-r--r--components/layout_2020/geom.rs9
2 files changed, 90 insertions, 95 deletions
diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs
index 219fdbdcfb8..d7b9854668a 100644
--- a/components/layout_2020/flow/mod.rs
+++ b/components/layout_2020/flow/mod.rs
@@ -20,7 +20,7 @@ use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIter
use rayon_croissant::ParallelIteratorExt;
use servo_arc::Arc;
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::Zero;
@@ -354,16 +354,16 @@ fn layout_in_flow_non_replaced_block_level<'a>(
) -> FlowLayout,
) -> BoxFragment {
let cbis = containing_block.inline_size;
- let cbbs = containing_block.block_size.non_auto();
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();
- let max_box_size = style.max_box_size();
- let min_box_size = style.min_box_size();
+ let box_size = percent_resolved_box_size(style.box_size(), containing_block);
+ let max_box_size = percent_resolved_max_box_size(style.max_box_size(), containing_block);
+ 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
let solve_inline_margins = |inline_size| {
@@ -376,7 +376,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
)
};
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))
} else {
let margin_inline_start = margin.inline_start.auto_is(Length::zero);
@@ -385,19 +385,14 @@ fn layout_in_flow_non_replaced_block_level<'a>(
let inline_size = cbis - pb_inline_sum - margin_inline_sum;
(inline_size, (margin_inline_start, margin_inline_end))
};
- if let MaxSize::LengthPercentage(max_inline_size) = max_box_size.inline {
- let max_inline_size = max_inline_size.percentage_relative_to(cbis);
+ if let Some(max_inline_size) = max_box_size.inline {
if inline_size > max_inline_size {
inline_size = max_inline_size;
inline_margins = solve_inline_margins(inline_size);
}
}
- let min_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;
+ if inline_size < min_box_size.inline {
+ inline_size = min_box_size.inline;
inline_margins = solve_inline_margins(inline_size);
}
@@ -409,19 +404,9 @@ fn layout_in_flow_non_replaced_block_level<'a>(
};
// https://drafts.csswg.org/css2/visudet.html#min-max-heights
- 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 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);
+ let mut block_size = box_size.block;
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 {
@@ -440,7 +425,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
pb.block_start == Length::zero(),
);
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() &&
block_level_kind == BlockLevelKind::SameFormattingContextBlock;
let mut nested_abspos = vec![];
@@ -487,8 +472,8 @@ fn layout_in_flow_non_replaced_block_level<'a>(
let block_size = block_size.auto_is(|| {
clamp_between_extremums(
flow_layout.content_block_size,
- min_block_size,
- max_block_size,
+ min_box_size.block,
+ max_box_size.block,
)
});
let content_rect = Rect {
@@ -531,7 +516,6 @@ fn layout_in_flow_replaced_block_level<'a>(
replaced: &ReplacedContent,
) -> BoxFragment {
let cbis = containing_block.inline_size;
- let cbbs = containing_block.block_size.non_auto();
let padding = style.padding().percentages_relative_to(cbis);
let border = style.border_width();
let computed_margin = style.margin().percentages_relative_to(cbis);
@@ -542,41 +526,20 @@ fn layout_in_flow_replaced_block_level<'a>(
// FIXME(nox): This can divide by zero.
let intrinsic_ratio = intrinsic_size.inline.px() / intrinsic_size.block.px();
- let box_size = style.box_size();
- let min_box_size = style.min_box_size();
- let max_box_size = style.max_box_size();
-
- 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 box_size = percent_resolved_box_size(style.box_size(), containing_block);
+ let min_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 clamp = |inline_size, block_size| {
(
- clamp_between_extremums(inline_size, min_inline_size, max_inline_size),
- clamp_between_extremums(block_size, min_block_size, max_block_size),
+ clamp_between_extremums(inline_size, min_box_size.inline, max_box_size.inline),
+ 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-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)) => {
clamp(inline, block)
},
@@ -605,39 +568,35 @@ fn layout_in_flow_replaced_block_level<'a>(
}
};
match (
- violation(intrinsic_size.inline, min_inline_size, max_inline_size),
- violation(intrinsic_size.block, min_block_size, max_block_size),
+ violation(
+ 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.
(Violation::None, Violation::None) => (intrinsic_size.inline, intrinsic_size.block),
// Row 2.
(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)
},
// Row 3.
(Violation::Below(min_inline_size), Violation::None) => {
- let mut block_size = min_inline_size / intrinsic_ratio;
- if let Some(max_block_size) = max_block_size {
- if block_size > max_block_size {
- block_size = max_block_size;
- }
- }
+ let block_size =
+ clamp_below_max(min_inline_size / intrinsic_ratio, max_box_size.block);
(min_inline_size, block_size)
},
// Row 4.
(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)
},
// Row 5.
(Violation::None, Violation::Below(min_block_size)) => {
- let mut inline_size = min_block_size * intrinsic_ratio;
- if let Some(max_inline_size) = max_inline_size {
- if inline_size > max_inline_size {
- inline_size = max_inline_size;
- }
- }
+ let inline_size =
+ clamp_below_max(min_block_size * intrinsic_ratio, max_box_size.inline);
(inline_size, min_block_size)
},
// Rows 6-7.
@@ -646,11 +605,13 @@ fn layout_in_flow_replaced_block_level<'a>(
max_block_size.px() / intrinsic_size.block.px()
{
// 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)
} else {
// 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)
}
},
@@ -660,21 +621,13 @@ fn layout_in_flow_replaced_block_level<'a>(
min_block_size.px() / intrinsic_size.block.px()
{
// Row 8.
- let mut inline_size = min_block_size * intrinsic_ratio;
- if let Some(max_inline_size) = max_inline_size {
- if inline_size > max_inline_size {
- inline_size = max_inline_size;
- }
- }
+ let inline_size =
+ clamp_below_max(min_block_size * intrinsic_ratio, max_box_size.inline);
(inline_size, min_block_size)
} else {
// Row 9.
- let mut block_size = min_inline_size / intrinsic_ratio;
- if let Some(max_block_size) = max_block_size {
- if block_size > max_block_size {
- block_size = max_block_size;
- }
- }
+ let block_size =
+ clamp_below_max(min_inline_size / intrinsic_ratio, max_box_size.block);
(min_inline_size, block_size)
}
},
@@ -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 {
- if let Some(max_size) = max_size {
- if size > max_size {
- size = max_size;
- }
+fn clamp_between_extremums(size: Length, min_size: Length, max_size: Option<Length>) -> Length {
+ clamp_below_max(size, max_size).max(min_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)
}
diff --git a/components/layout_2020/geom.rs b/components/layout_2020/geom.rs
index d75a1634561..39c7cb331e4 100644
--- a/components/layout_2020/geom.rs
+++ b/components/layout_2020/geom.rs
@@ -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> {
pub fn zero() -> Self {
Self {