mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
layout: make AxisResult
, Anchor
& AbsoluteAxisSolver
use Au
(#31395)
* make AxisResult and Anchor use Au * Avoid some .into() * review fix * review update --------- Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
a97a04d84c
commit
304ab9b09c
2 changed files with 102 additions and 108 deletions
|
@ -70,6 +70,13 @@ impl<T: Clone> LogicalVec2<T> {
|
|||
block: b.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map<U>(&self, f: impl Fn(&T) -> U) -> LogicalVec2<U> {
|
||||
LogicalVec2 {
|
||||
inline: f(&self.inline),
|
||||
block: f(&self.block),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add<&'_ LogicalVec2<T>> for &'_ LogicalVec2<T>
|
||||
|
@ -121,10 +128,7 @@ impl<T: Zero> LogicalVec2<T> {
|
|||
|
||||
impl LogicalVec2<LengthOrAuto> {
|
||||
pub fn auto_is(&self, f: impl Fn() -> Length) -> LogicalVec2<Length> {
|
||||
LogicalVec2 {
|
||||
inline: self.inline.auto_is(&f),
|
||||
block: self.block.auto_is(&f),
|
||||
}
|
||||
self.map(|t| t.auto_is(&f))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -479,14 +483,8 @@ impl From<LogicalVec2<Au>> for LogicalVec2<CSSPixelLength> {
|
|||
impl From<LogicalRect<Au>> for LogicalRect<CSSPixelLength> {
|
||||
fn from(value: LogicalRect<Au>) -> Self {
|
||||
LogicalRect {
|
||||
start_corner: LogicalVec2 {
|
||||
inline: value.start_corner.inline.into(),
|
||||
block: value.start_corner.block.into(),
|
||||
},
|
||||
size: LogicalVec2 {
|
||||
inline: value.size.inline.into(),
|
||||
block: value.size.block.into(),
|
||||
},
|
||||
start_corner: value.start_corner.into(),
|
||||
size: value.size.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -494,14 +492,8 @@ impl From<LogicalRect<Au>> for LogicalRect<CSSPixelLength> {
|
|||
impl From<LogicalRect<CSSPixelLength>> for LogicalRect<Au> {
|
||||
fn from(value: LogicalRect<CSSPixelLength>) -> Self {
|
||||
LogicalRect {
|
||||
start_corner: LogicalVec2 {
|
||||
inline: value.start_corner.inline.into(),
|
||||
block: value.start_corner.block.into(),
|
||||
},
|
||||
size: LogicalVec2 {
|
||||
inline: value.size.inline.into(),
|
||||
block: value.size.block.into(),
|
||||
},
|
||||
start_corner: value.start_corner.into(),
|
||||
size: value.size.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -502,19 +502,19 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
|
||||
let shared_fragment = self.fragment.borrow();
|
||||
let inline_axis_solver = AbsoluteAxisSolver {
|
||||
containing_size: cbis.into(),
|
||||
padding_border_sum: pbm.padding_border_sums.inline.into(),
|
||||
computed_margin_start: pbm.margin.inline_start,
|
||||
computed_margin_end: pbm.margin.inline_end,
|
||||
containing_size: cbis,
|
||||
padding_border_sum: pbm.padding_border_sums.inline,
|
||||
computed_margin_start: pbm.margin.inline_start.map(|t| t.into()),
|
||||
computed_margin_end: pbm.margin.inline_end.map(|t| t.into()),
|
||||
avoid_negative_margin_start: true,
|
||||
box_offsets: &shared_fragment.box_offsets.inline,
|
||||
};
|
||||
|
||||
let block_axis_solver = AbsoluteAxisSolver {
|
||||
containing_size: cbbs.into(),
|
||||
padding_border_sum: pbm.padding_border_sums.block.into(),
|
||||
computed_margin_start: pbm.margin.block_start,
|
||||
computed_margin_end: pbm.margin.block_end,
|
||||
containing_size: cbbs,
|
||||
padding_border_sum: pbm.padding_border_sums.block,
|
||||
computed_margin_start: pbm.margin.block_start.map(|t| t.into()),
|
||||
computed_margin_end: pbm.margin.block_end.map(|t| t.into()),
|
||||
avoid_negative_margin_start: false,
|
||||
box_offsets: &shared_fragment.box_offsets.block,
|
||||
};
|
||||
|
@ -523,23 +523,25 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
block: block_axis_solver.is_overconstrained_for_size(computed_size.block),
|
||||
};
|
||||
|
||||
let mut inline_axis = inline_axis_solver.solve_for_size(computed_size.inline);
|
||||
let mut block_axis = block_axis_solver.solve_for_size(computed_size.block);
|
||||
let mut inline_axis =
|
||||
inline_axis_solver.solve_for_size(computed_size.inline.map(|t| t.into()));
|
||||
let mut block_axis =
|
||||
block_axis_solver.solve_for_size(computed_size.block.map(|t| t.into()));
|
||||
|
||||
let mut positioning_context =
|
||||
PositioningContext::new_for_style(absolutely_positioned_box.context.style()).unwrap();
|
||||
let mut new_fragment = {
|
||||
let content_size;
|
||||
let content_size: LogicalVec2<Au>;
|
||||
let fragments;
|
||||
match &mut absolutely_positioned_box.context {
|
||||
IndependentFormattingContext::Replaced(replaced) => {
|
||||
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
|
||||
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
|
||||
let style = &replaced.style;
|
||||
content_size = computed_size.auto_is(|| unreachable!());
|
||||
content_size = computed_size.auto_is(|| unreachable!()).into();
|
||||
fragments = replaced
|
||||
.contents
|
||||
.make_fragments(style, content_size.clone().into());
|
||||
.make_fragments(style, content_size.clone());
|
||||
},
|
||||
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
||||
// https://drafts.csswg.org/css2/#min-max-widths
|
||||
|
@ -547,10 +549,11 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
let min_size = non_replaced
|
||||
.style
|
||||
.content_min_box_size(&containing_block.into(), &pbm)
|
||||
.auto_is(Length::zero);
|
||||
.map(|t| t.map(Au::from).auto_is(Au::zero));
|
||||
let max_size = non_replaced
|
||||
.style
|
||||
.content_max_box_size(&containing_block.into(), &pbm);
|
||||
.content_max_box_size(&containing_block.into(), &pbm)
|
||||
.map(|t| t.map(Au::from));
|
||||
|
||||
// https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width
|
||||
// https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-height
|
||||
|
@ -560,14 +563,11 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
Anchor::End(end) => end,
|
||||
};
|
||||
let margin_sum = inline_axis.margin_start + inline_axis.margin_end;
|
||||
let available_size = cbis -
|
||||
anchor.into() -
|
||||
pbm.padding_border_sums.inline -
|
||||
margin_sum.into();
|
||||
let available_size =
|
||||
cbis - anchor - pbm.padding_border_sums.inline - margin_sum;
|
||||
non_replaced
|
||||
.inline_content_sizes(layout_context)
|
||||
.shrink_to_fit(available_size)
|
||||
.into()
|
||||
});
|
||||
|
||||
// If the tentative used inline size is greater than ‘max-inline-size’,
|
||||
|
@ -577,8 +577,8 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
// https://drafts.csswg.org/css2/#min-max-widths (step 2)
|
||||
if let Some(max) = max_size.inline {
|
||||
if inline_size > max {
|
||||
inline_axis = inline_axis_solver
|
||||
.solve_for_size(LengthOrAuto::LengthPercentage(max));
|
||||
inline_axis =
|
||||
inline_axis_solver.solve_for_size(AuOrAuto::LengthPercentage(max));
|
||||
inline_size = inline_axis.size.auto_is(|| unreachable!());
|
||||
}
|
||||
}
|
||||
|
@ -590,12 +590,12 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
// https://drafts.csswg.org/css2/#min-max-widths (step 3)
|
||||
if inline_size < min_size.inline {
|
||||
inline_axis = inline_axis_solver
|
||||
.solve_for_size(LengthOrAuto::LengthPercentage(min_size.inline));
|
||||
.solve_for_size(AuOrAuto::LengthPercentage(min_size.inline));
|
||||
inline_size = inline_axis.size.auto_is(|| unreachable!());
|
||||
}
|
||||
|
||||
struct Result {
|
||||
content_size: LogicalVec2<CSSPixelLength>,
|
||||
content_size: LogicalVec2<Au>,
|
||||
fragments: Vec<Fragment>,
|
||||
}
|
||||
|
||||
|
@ -604,7 +604,7 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
// percentages may be resolved incorrectly.
|
||||
let mut try_layout = |size| {
|
||||
let containing_block_for_children = ContainingBlock {
|
||||
inline_size: inline_size.into(),
|
||||
inline_size,
|
||||
block_size: size,
|
||||
style: &non_replaced.style,
|
||||
};
|
||||
|
@ -630,13 +630,13 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
Result {
|
||||
content_size: LogicalVec2 {
|
||||
inline: inline_size,
|
||||
block: block_size.into(),
|
||||
block: block_size,
|
||||
},
|
||||
fragments: independent_layout.fragments,
|
||||
}
|
||||
};
|
||||
|
||||
let mut result = try_layout(block_axis.size.map(|t| t.into()));
|
||||
let mut result = try_layout(block_axis.size);
|
||||
|
||||
// If the tentative used block size is greater than ‘max-block-size’,
|
||||
// recalculate the block size and margins with ‘max-block-size’ as the
|
||||
|
@ -645,9 +645,9 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
// https://drafts.csswg.org/css2/#min-max-heights (step 2)
|
||||
if let Some(max) = max_size.block {
|
||||
if result.content_size.block > max {
|
||||
block_axis = block_axis_solver
|
||||
.solve_for_size(LengthOrAuto::LengthPercentage(max));
|
||||
result = try_layout(AuOrAuto::LengthPercentage(max.into()));
|
||||
block_axis =
|
||||
block_axis_solver.solve_for_size(AuOrAuto::LengthPercentage(max));
|
||||
result = try_layout(AuOrAuto::LengthPercentage(max));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -658,8 +658,8 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
// https://drafts.csswg.org/css2/#min-max-heights (step 3)
|
||||
if result.content_size.block < min_size.block {
|
||||
block_axis = block_axis_solver
|
||||
.solve_for_size(LengthOrAuto::LengthPercentage(min_size.block));
|
||||
result = try_layout(AuOrAuto::LengthPercentage(min_size.block.into()));
|
||||
.solve_for_size(AuOrAuto::LengthPercentage(min_size.block));
|
||||
result = try_layout(AuOrAuto::LengthPercentage(min_size.block));
|
||||
}
|
||||
|
||||
content_size = result.content_size;
|
||||
|
@ -676,22 +676,16 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
|
||||
let pb = &pbm.padding + &pbm.border;
|
||||
let inline_start = match inline_axis.anchor {
|
||||
Anchor::Start(start) => start + pb.inline_start.into() + margin.inline_start,
|
||||
Anchor::End(end) => Length::from(
|
||||
cbis - end.into() -
|
||||
pb.inline_end -
|
||||
margin.inline_end.into() -
|
||||
content_size.inline.into(),
|
||||
),
|
||||
Anchor::Start(start) => start + pb.inline_start + margin.inline_start,
|
||||
Anchor::End(end) => {
|
||||
cbis - end - pb.inline_end - margin.inline_end - content_size.inline
|
||||
},
|
||||
};
|
||||
let block_start = match block_axis.anchor {
|
||||
Anchor::Start(start) => start + pb.block_start.into() + margin.block_start,
|
||||
Anchor::End(end) => Length::from(
|
||||
cbbs - end.into() -
|
||||
pb.block_end -
|
||||
margin.block_end.into() -
|
||||
content_size.block.into(),
|
||||
),
|
||||
Anchor::Start(start) => start + pb.block_start + margin.block_start,
|
||||
Anchor::End(end) => {
|
||||
cbbs - end - pb.block_end - margin.block_end - content_size.block
|
||||
},
|
||||
};
|
||||
|
||||
let content_rect = LogicalRect {
|
||||
|
@ -709,10 +703,10 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
absolutely_positioned_box.context.base_fragment_info(),
|
||||
absolutely_positioned_box.context.style().clone(),
|
||||
fragments,
|
||||
content_rect,
|
||||
content_rect.into(),
|
||||
pbm.padding.into(),
|
||||
pbm.border.into(),
|
||||
margin,
|
||||
margin.into(),
|
||||
None, /* clearance */
|
||||
// We do not set the baseline offset, because absolutely positioned
|
||||
// elements are not inflow.
|
||||
|
@ -740,22 +734,22 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
}
|
||||
|
||||
enum Anchor {
|
||||
Start(Length),
|
||||
End(Length),
|
||||
Start(Au),
|
||||
End(Au),
|
||||
}
|
||||
|
||||
struct AxisResult {
|
||||
anchor: Anchor,
|
||||
size: LengthOrAuto,
|
||||
margin_start: Length,
|
||||
margin_end: Length,
|
||||
size: AuOrAuto,
|
||||
margin_start: Au,
|
||||
margin_end: Au,
|
||||
}
|
||||
|
||||
struct AbsoluteAxisSolver<'a> {
|
||||
containing_size: Length,
|
||||
padding_border_sum: Length,
|
||||
computed_margin_start: LengthOrAuto,
|
||||
computed_margin_end: LengthOrAuto,
|
||||
containing_size: Au,
|
||||
padding_border_sum: Au,
|
||||
computed_margin_start: AuOrAuto,
|
||||
computed_margin_end: AuOrAuto,
|
||||
avoid_negative_margin_start: bool,
|
||||
box_offsets: &'a AbsoluteBoxOffsets,
|
||||
}
|
||||
|
@ -772,78 +766,86 @@ impl<'a> AbsoluteAxisSolver<'a> {
|
|||
/// * <https://drafts.csswg.org/css2/visudet.html#abs-replaced-height>
|
||||
///
|
||||
/// In the replaced case, `size` is never `Auto`.
|
||||
fn solve_for_size(&self, computed_size: LengthOrAuto) -> AxisResult {
|
||||
fn solve_for_size(&self, computed_size: AuOrAuto) -> AxisResult {
|
||||
match self.box_offsets {
|
||||
AbsoluteBoxOffsets::StaticStart { start } => AxisResult {
|
||||
anchor: Anchor::Start(*start),
|
||||
anchor: Anchor::Start((*start).into()),
|
||||
size: computed_size,
|
||||
margin_start: self.computed_margin_start.auto_is(Length::zero),
|
||||
margin_end: self.computed_margin_end.auto_is(Length::zero),
|
||||
margin_start: self.computed_margin_start.auto_is(Au::zero),
|
||||
margin_end: self.computed_margin_end.auto_is(Au::zero),
|
||||
},
|
||||
AbsoluteBoxOffsets::Start { start } => AxisResult {
|
||||
anchor: Anchor::Start(start.percentage_relative_to(self.containing_size)),
|
||||
anchor: Anchor::Start(
|
||||
start
|
||||
.percentage_relative_to(self.containing_size.into())
|
||||
.into(),
|
||||
),
|
||||
size: computed_size,
|
||||
margin_start: self.computed_margin_start.auto_is(Length::zero),
|
||||
margin_end: self.computed_margin_end.auto_is(Length::zero),
|
||||
margin_start: self.computed_margin_start.auto_is(Au::zero),
|
||||
margin_end: self.computed_margin_end.auto_is(Au::zero),
|
||||
},
|
||||
AbsoluteBoxOffsets::End { end } => AxisResult {
|
||||
anchor: Anchor::End(end.percentage_relative_to(self.containing_size)),
|
||||
anchor: Anchor::End(
|
||||
end.percentage_relative_to(self.containing_size.into())
|
||||
.into(),
|
||||
),
|
||||
size: computed_size,
|
||||
margin_start: self.computed_margin_start.auto_is(Length::zero),
|
||||
margin_end: self.computed_margin_end.auto_is(Length::zero),
|
||||
margin_start: self.computed_margin_start.auto_is(Au::zero),
|
||||
margin_end: self.computed_margin_end.auto_is(Au::zero),
|
||||
},
|
||||
AbsoluteBoxOffsets::Both { start, end } => {
|
||||
let start = start.percentage_relative_to(self.containing_size);
|
||||
let end = end.percentage_relative_to(self.containing_size);
|
||||
let start = start.percentage_relative_to(self.containing_size.into());
|
||||
let end = end.percentage_relative_to(self.containing_size.into());
|
||||
|
||||
let margin_start;
|
||||
let margin_end;
|
||||
let used_size;
|
||||
if let LengthOrAuto::LengthPercentage(s) = computed_size {
|
||||
if let AuOrAuto::LengthPercentage(s) = computed_size {
|
||||
used_size = s;
|
||||
let margins = self.containing_size - start - end - self.padding_border_sum - s;
|
||||
let margins = self.containing_size -
|
||||
start.into() -
|
||||
end.into() -
|
||||
self.padding_border_sum -
|
||||
s;
|
||||
match (self.computed_margin_start, self.computed_margin_end) {
|
||||
(LengthOrAuto::Auto, LengthOrAuto::Auto) => {
|
||||
if self.avoid_negative_margin_start && margins < Length::zero() {
|
||||
margin_start = Length::zero();
|
||||
(AuOrAuto::Auto, AuOrAuto::Auto) => {
|
||||
if self.avoid_negative_margin_start && margins < Au::zero() {
|
||||
margin_start = Au::zero();
|
||||
margin_end = margins;
|
||||
} else {
|
||||
margin_start = margins / 2.;
|
||||
margin_end = margins / 2.;
|
||||
margin_start = margins / 2;
|
||||
margin_end = margins - margin_start;
|
||||
}
|
||||
},
|
||||
(LengthOrAuto::Auto, LengthOrAuto::LengthPercentage(end)) => {
|
||||
(AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => {
|
||||
margin_start = margins - end;
|
||||
margin_end = end;
|
||||
},
|
||||
(LengthOrAuto::LengthPercentage(start), LengthOrAuto::Auto) => {
|
||||
(AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => {
|
||||
margin_start = start;
|
||||
margin_end = margins - start;
|
||||
},
|
||||
(
|
||||
LengthOrAuto::LengthPercentage(start),
|
||||
LengthOrAuto::LengthPercentage(end),
|
||||
) => {
|
||||
(AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => {
|
||||
margin_start = start;
|
||||
margin_end = end;
|
||||
},
|
||||
}
|
||||
} else {
|
||||
margin_start = self.computed_margin_start.auto_is(Length::zero);
|
||||
margin_end = self.computed_margin_end.auto_is(Length::zero);
|
||||
margin_start = self.computed_margin_start.auto_is(Au::zero);
|
||||
margin_end = self.computed_margin_end.auto_is(Au::zero);
|
||||
|
||||
// This may be negative, but the caller will later effectively
|
||||
// clamp it to ‘min-inline-size’ or ‘min-block-size’.
|
||||
used_size = self.containing_size -
|
||||
start -
|
||||
end -
|
||||
start.into() -
|
||||
end.into() -
|
||||
self.padding_border_sum -
|
||||
margin_start -
|
||||
margin_end;
|
||||
};
|
||||
AxisResult {
|
||||
anchor: Anchor::Start(start),
|
||||
size: LengthOrAuto::LengthPercentage(used_size),
|
||||
anchor: Anchor::Start(start.into()),
|
||||
size: AuOrAuto::LengthPercentage(used_size),
|
||||
margin_start,
|
||||
margin_end,
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue