mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Consistent resolution of cyclic percentages in min sizing properties (#33988)
The spec says that cyclic percentages in min sizing properties should be resolved against zero when computing intrinsic contributions. We were already doing that in the inline axis, but we were treating the entire expression as `auto` in the block axis. With this patch we will follow the spec in both axes. But note that browsers don't follo the spec in either axis, so we may have to revisit (see https://github.com/w3c/csswg-drafts/issues/10969). calc-min-height-block-1.html now fails because it tests what browsers do instead of what the spec says. Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
202cb53d5b
commit
9ad59d1459
5 changed files with 125 additions and 43 deletions
|
@ -67,6 +67,29 @@ impl<T: Default> Default for LogicalVec2<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> LogicalVec2<T> {
|
||||
pub fn map_inline_and_block_axes<U>(
|
||||
&self,
|
||||
inline_f: impl FnOnce(&T) -> U,
|
||||
block_f: impl FnOnce(&T) -> U,
|
||||
) -> LogicalVec2<U> {
|
||||
LogicalVec2 {
|
||||
inline: inline_f(&self.inline),
|
||||
block: block_f(&self.block),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> LogicalVec2<Size<T>> {
|
||||
pub fn map_inline_and_block_sizes<U>(
|
||||
&self,
|
||||
inline_f: impl FnOnce(T) -> U,
|
||||
block_f: impl FnOnce(T) -> U,
|
||||
) -> LogicalVec2<Size<U>> {
|
||||
self.map_inline_and_block_axes(|size| size.map(inline_f), |size| size.map(block_f))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> LogicalVec2<T> {
|
||||
pub fn from_physical_size(physical_size: &PhysicalSize<T>, mode: WritingMode) -> Self {
|
||||
// https://drafts.csswg.org/css-writing-modes/#logical-to-physical
|
||||
|
@ -734,15 +757,14 @@ impl LogicalVec2<Size<LengthPercentage>> {
|
|||
&self,
|
||||
containing_block: &ContainingBlock,
|
||||
) -> LogicalVec2<Size<Au>> {
|
||||
LogicalVec2 {
|
||||
inline: self
|
||||
.inline
|
||||
.map(|lp| lp.to_used_value(containing_block.inline_size)),
|
||||
block: self
|
||||
.block
|
||||
.maybe_map(|lp| lp.maybe_to_used_value(containing_block.block_size.non_auto()))
|
||||
.unwrap_or_default(),
|
||||
}
|
||||
self.map_inline_and_block_axes(
|
||||
|inline_size| inline_size.map(|lp| lp.to_used_value(containing_block.inline_size)),
|
||||
|block_size| {
|
||||
block_size
|
||||
.maybe_map(|lp| lp.maybe_to_used_value(containing_block.block_size.non_auto()))
|
||||
.unwrap_or_default()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn maybe_percentages_relative_to_basis(
|
||||
|
|
|
@ -413,16 +413,12 @@ impl ComputedValuesExt for ComputedValues {
|
|||
) -> LogicalVec2<Size<Au>> {
|
||||
match self.get_position().box_sizing {
|
||||
BoxSizing::ContentBox => box_size,
|
||||
BoxSizing::BorderBox => LogicalVec2 {
|
||||
// These may be negative, but will later be clamped by `min-width`/`min-height`
|
||||
// which is clamped to zero.
|
||||
inline: box_size
|
||||
.inline
|
||||
.map(|value| value - pbm.padding_border_sums.inline),
|
||||
block: box_size
|
||||
.block
|
||||
.map(|value| value - pbm.padding_border_sums.block),
|
||||
},
|
||||
// These may be negative, but will later be clamped by `min-width`/`min-height`
|
||||
// which is clamped to zero.
|
||||
BoxSizing::BorderBox => box_size.map_inline_and_block_sizes(
|
||||
|value| value - pbm.padding_border_sums.inline,
|
||||
|value| value - pbm.padding_border_sums.block,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,10 +427,13 @@ impl ComputedValuesExt for ComputedValues {
|
|||
containing_block: &ContainingBlock,
|
||||
pbm: &PaddingBorderMargin,
|
||||
) -> LogicalVec2<Size<Au>> {
|
||||
let box_size = self
|
||||
let min_size = self
|
||||
.min_box_size(containing_block.style.writing_mode)
|
||||
.percentages_relative_to(containing_block);
|
||||
self.content_min_box_size_for_min_size(box_size, pbm)
|
||||
.map_inline_and_block_sizes(
|
||||
|lp| lp.to_used_value(containing_block.inline_size),
|
||||
|lp| lp.to_used_value(containing_block.block_size.auto_is(Au::zero)),
|
||||
);
|
||||
self.content_min_box_size_for_min_size(min_size, pbm)
|
||||
}
|
||||
|
||||
fn content_min_box_size_deprecated(
|
||||
|
@ -453,15 +452,11 @@ impl ComputedValuesExt for ComputedValues {
|
|||
) -> LogicalVec2<Size<Au>> {
|
||||
match self.get_position().box_sizing {
|
||||
BoxSizing::ContentBox => min_box_size,
|
||||
BoxSizing::BorderBox => LogicalVec2 {
|
||||
// Clamp to zero to make sure the used size components are non-negative
|
||||
inline: min_box_size
|
||||
.inline
|
||||
.map(|value| (value - pbm.padding_border_sums.inline).max(Au::zero())),
|
||||
block: min_box_size
|
||||
.block
|
||||
.map(|value| (value - pbm.padding_border_sums.block).max(Au::zero())),
|
||||
},
|
||||
// Clamp to zero to make sure the used size components are non-negative
|
||||
BoxSizing::BorderBox => min_box_size.map_inline_and_block_sizes(
|
||||
|value| Au::zero().max(value - pbm.padding_border_sums.inline),
|
||||
|value| Au::zero().max(value - pbm.padding_border_sums.block),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -493,18 +488,12 @@ impl ComputedValuesExt for ComputedValues {
|
|||
) -> LogicalVec2<Size<Au>> {
|
||||
match self.get_position().box_sizing {
|
||||
BoxSizing::ContentBox => max_box_size,
|
||||
BoxSizing::BorderBox => {
|
||||
// This may be negative, but will later be clamped by `min-width`
|
||||
// which itself is clamped to zero.
|
||||
LogicalVec2 {
|
||||
inline: max_box_size
|
||||
.inline
|
||||
.map(|value| value - pbm.padding_border_sums.inline),
|
||||
block: max_box_size
|
||||
.block
|
||||
.map(|value| value - pbm.padding_border_sums.block),
|
||||
}
|
||||
},
|
||||
// This may be negative, but will later be clamped by `min-width`
|
||||
// which itself is clamped to zero.
|
||||
BoxSizing::BorderBox => max_box_size.map_inline_and_block_sizes(
|
||||
|value| value - pbm.padding_border_sums.inline,
|
||||
|value| value - pbm.padding_border_sums.block,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
7
tests/wpt/meta/MANIFEST.json
vendored
7
tests/wpt/meta/MANIFEST.json
vendored
|
@ -569282,6 +569282,13 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"intrinsic-percent-non-replaced-006.html": [
|
||||
"48b8c42ae3074011cd32bf3f44e1a40648ec5c7d",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"intrinsic-size-fallback-replaced.html": [
|
||||
"a3325b0aea01c008ec322a20e0f279d5bd765b1c",
|
||||
[
|
||||
|
|
2
tests/wpt/meta/css/css-values/calc-min-height-block-1.html.ini
vendored
Normal file
2
tests/wpt/meta/css/css-values/calc-min-height-block-1.html.ini
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
[calc-min-height-block-1.html]
|
||||
expected: FAIL
|
62
tests/wpt/tests/css/css-sizing/intrinsic-percent-non-replaced-006.html
vendored
Normal file
62
tests/wpt/tests/css/css-sizing/intrinsic-percent-non-replaced-006.html
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Cyclic percentages in min-width and min-height</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#cyclic-percentage-contribution">
|
||||
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/10969">
|
||||
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
|
||||
|
||||
<style>
|
||||
#outer {
|
||||
display: inline-block;
|
||||
border: 5px solid;
|
||||
padding: 3px;
|
||||
}
|
||||
#inner {
|
||||
min-width: calc(100px + 50%);
|
||||
min-height: calc(100px + 50%);
|
||||
border: 2px solid cyan;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="outer">
|
||||
<div id="inner"></div>
|
||||
</div>
|
||||
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
const innerBorder = 4;
|
||||
const outerPadding = 6;
|
||||
const bp = innerBorder + outerPadding;
|
||||
|
||||
// Intrinsic contributions should treat cyclic percentages equally in both axes.
|
||||
test(
|
||||
() => assert_equals(outer.clientWidth, outer.clientHeight),
|
||||
"Axis consistency of intrinsic contributions",
|
||||
);
|
||||
|
||||
// The spec says that the intrinsic size contributions should resolve cyclic percentages
|
||||
// in min size properties against zero, so here we should expect 110px.
|
||||
// However, most browsers just ignore the mininum in that case, resulting in 10px.
|
||||
// See https://github.com/w3c/csswg-drafts/issues/10969
|
||||
test(
|
||||
() => assert_in_array(outer.clientWidth, [0 + bp, 100 + bp]),
|
||||
"Intrinsic contribution for width",
|
||||
);
|
||||
test(
|
||||
() => assert_in_array(outer.clientHeight, [0 + bp, 100 + bp]),
|
||||
"Intrinsic contribution for height",
|
||||
);
|
||||
|
||||
// Regardless of how browsers treat cyclic percentages, once the size of #outer is known,
|
||||
// #inner should re-resolve its inline-axis percentage against the containing block,
|
||||
// but not re-resolve its block-axis percentage.
|
||||
test(
|
||||
() => assert_equals(inner.clientWidth, 100 + 0.5 * (outer.clientWidth - outerPadding)),
|
||||
"Final size for width",
|
||||
);
|
||||
test(
|
||||
() => assert_equals(inner.clientHeight, outer.clientHeight - bp),
|
||||
"Final size for height",
|
||||
);
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue