mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Implement keyword sizes on atomic inlines (#33737)
Adds support for min-content, max-content, fit-content and stretch, for atomic inlines. There are some new test failures because we don't support vertical writing modes nor `transition-behavior:allow-discrete`. Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
52cddb45bd
commit
8c56cbdab2
6 changed files with 248 additions and 41 deletions
|
@ -123,11 +123,11 @@ use crate::fragment_tree::{
|
|||
BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags,
|
||||
PositioningFragment,
|
||||
};
|
||||
use crate::geom::{LogicalRect, LogicalVec2, PhysicalPoint, PhysicalRect, ToLogical};
|
||||
use crate::geom::{LogicalRect, LogicalVec2, PhysicalPoint, PhysicalRect, Size, ToLogical};
|
||||
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
|
||||
use crate::sizing::ContentSizes;
|
||||
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
|
||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
||||
use crate::{AuOrAuto, ContainingBlock, IndefiniteContainingBlock};
|
||||
|
||||
// From gfxFontConstants.h in Firefox.
|
||||
static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
|
||||
|
@ -1932,42 +1932,70 @@ impl IndependentFormattingContext {
|
|||
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
||||
let box_size = non_replaced
|
||||
.style
|
||||
.content_box_size_deprecated(layout.containing_block, &pbm)
|
||||
.map(|v| v.map(Au::from));
|
||||
.content_box_size(layout.containing_block, &pbm);
|
||||
let max_box_size = non_replaced
|
||||
.style
|
||||
.content_max_box_size_deprecated(layout.containing_block, &pbm)
|
||||
.map(|v| v.map(Au::from));
|
||||
.content_max_box_size(layout.containing_block, &pbm);
|
||||
let min_box_size = non_replaced
|
||||
.style
|
||||
.content_min_box_size_deprecated(layout.containing_block, &pbm)
|
||||
.map(|v| v.map(Au::from))
|
||||
.auto_is(Au::zero);
|
||||
let block_size = box_size
|
||||
.block
|
||||
.map(|v| v.clamp_between_extremums(min_box_size.block, max_box_size.block));
|
||||
.content_min_box_size(layout.containing_block, &pbm);
|
||||
|
||||
// https://drafts.csswg.org/css2/visudet.html#inlineblock-width
|
||||
let tentative_inline_size = box_size.inline.auto_is(|| {
|
||||
let style = non_replaced.style.clone();
|
||||
let available_inline_size =
|
||||
layout.containing_block.inline_size - pbm_sums.inline_sum();
|
||||
let available_block_size = layout
|
||||
.containing_block
|
||||
.block_size
|
||||
.non_auto()
|
||||
.map(|block_size| block_size - pbm_sums.block_sum());
|
||||
let tentative_block_size = box_size
|
||||
.block
|
||||
.maybe_resolve_extrinsic(available_block_size)
|
||||
.map(|v| {
|
||||
let min_block_size = min_box_size
|
||||
.block
|
||||
.maybe_resolve_extrinsic(available_block_size)
|
||||
.unwrap_or_default();
|
||||
let max_block_size = max_box_size
|
||||
.block
|
||||
.maybe_resolve_extrinsic(available_block_size);
|
||||
v.clamp_between_extremums(min_block_size, max_block_size)
|
||||
})
|
||||
.map_or(AuOrAuto::Auto, AuOrAuto::LengthPercentage);
|
||||
|
||||
let style = non_replaced.style.clone();
|
||||
let mut get_content_size = || {
|
||||
let containing_block_for_children =
|
||||
IndefiniteContainingBlock::new_for_style_and_block_size(&style, block_size);
|
||||
let available_size =
|
||||
layout.containing_block.inline_size - pbm_sums.inline_sum();
|
||||
IndefiniteContainingBlock::new_for_style_and_block_size(
|
||||
&style,
|
||||
tentative_block_size,
|
||||
);
|
||||
non_replaced
|
||||
.inline_content_sizes(layout.layout_context, &containing_block_for_children)
|
||||
.shrink_to_fit(available_size)
|
||||
});
|
||||
};
|
||||
|
||||
// https://drafts.csswg.org/css2/visudet.html#inlineblock-width
|
||||
let tentative_inline_size = box_size.inline.resolve(
|
||||
Size::fit_content,
|
||||
available_inline_size,
|
||||
&mut get_content_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 min_inline_size = min_box_size
|
||||
.inline
|
||||
.resolve_non_initial(available_inline_size, &mut get_content_size)
|
||||
.unwrap_or_default();
|
||||
let max_inline_size = max_box_size
|
||||
.inline
|
||||
.resolve_non_initial(available_inline_size, &mut get_content_size);
|
||||
let inline_size =
|
||||
tentative_inline_size.clamp_between_extremums(min_inline_size, max_inline_size);
|
||||
|
||||
let containing_block_for_children = ContainingBlock {
|
||||
inline_size,
|
||||
block_size,
|
||||
block_size: tentative_block_size,
|
||||
style: &non_replaced.style,
|
||||
};
|
||||
assert_eq!(
|
||||
|
@ -1988,22 +2016,28 @@ impl IndependentFormattingContext {
|
|||
&containing_block_for_children,
|
||||
layout.containing_block,
|
||||
);
|
||||
let (inline_size, block_size) =
|
||||
match independent_layout.content_inline_size_for_table {
|
||||
Some(inline) => (inline, independent_layout.content_block_size),
|
||||
None => {
|
||||
// https://drafts.csswg.org/css2/visudet.html#block-root-margin
|
||||
let block_size = block_size.auto_is(|| {
|
||||
// https://drafts.csswg.org/css2/visudet.html#min-max-heights
|
||||
// In this case “applying the rules above again” with a non-auto block-size
|
||||
// always results in that size.
|
||||
independent_layout
|
||||
.content_block_size
|
||||
.clamp_between_extremums(min_box_size.block, max_box_size.block)
|
||||
});
|
||||
(inline_size, block_size)
|
||||
},
|
||||
};
|
||||
let (inline_size, block_size) = match independent_layout
|
||||
.content_inline_size_for_table
|
||||
{
|
||||
Some(inline) => (inline, independent_layout.content_block_size),
|
||||
None => {
|
||||
// https://drafts.csswg.org/css2/visudet.html#block-root-margin
|
||||
let stretch_size =
|
||||
available_block_size.unwrap_or(independent_layout.content_block_size);
|
||||
let mut get_content_size = || independent_layout.content_block_size.into();
|
||||
let min_block_size = min_box_size
|
||||
.block
|
||||
.resolve_non_initial(stretch_size, &mut get_content_size)
|
||||
.unwrap_or_default();
|
||||
let max_block_size = max_box_size
|
||||
.block
|
||||
.resolve_non_initial(stretch_size, &mut get_content_size);
|
||||
let block_size = tentative_block_size
|
||||
.auto_is(|| independent_layout.content_block_size)
|
||||
.clamp_between_extremums(min_block_size, max_block_size);
|
||||
(inline_size, block_size)
|
||||
},
|
||||
};
|
||||
|
||||
let content_rect = PhysicalRect::new(
|
||||
PhysicalPoint::zero(),
|
||||
|
|
7
tests/wpt/meta/MANIFEST.json
vendored
7
tests/wpt/meta/MANIFEST.json
vendored
|
@ -565466,6 +565466,13 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"keyword-sizes-on-inline-block.html": [
|
||||
"a66e118c203678bae777c1fbd572a30dde6e0a5f",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"min-max-content-orthogonal-flow-crash-001.html": [
|
||||
"d2617f8aa2d1c966e394abb1d1617c012ea4648e",
|
||||
[
|
||||
|
|
|
@ -478,3 +478,21 @@
|
|||
|
||||
[Web Animations: property <height> from neutral to [fit-content\] at (1.5) should be [fit-content\]]
|
||||
expected: FAIL
|
||||
|
||||
[CSS Transitions with transition-behavior:allow-discrete: property <height> from [max-content\] to [stretch\] at (-0.3) should be [max-content\]]
|
||||
expected: FAIL
|
||||
|
||||
[CSS Transitions with transition-behavior:allow-discrete: property <height> from [max-content\] to [stretch\] at (0) should be [max-content\]]
|
||||
expected: FAIL
|
||||
|
||||
[CSS Transitions with transition-behavior:allow-discrete: property <height> from [max-content\] to [stretch\] at (0.3) should be [max-content\]]
|
||||
expected: FAIL
|
||||
|
||||
[CSS Transitions with transition-property:all and transition-behavor:allow-discrete: property <height> from [max-content\] to [stretch\] at (-0.3) should be [max-content\]]
|
||||
expected: FAIL
|
||||
|
||||
[CSS Transitions with transition-property:all and transition-behavor:allow-discrete: property <height> from [max-content\] to [stretch\] at (0) should be [max-content\]]
|
||||
expected: FAIL
|
||||
|
||||
[CSS Transitions with transition-property:all and transition-behavor:allow-discrete: property <height> from [max-content\] to [stretch\] at (0.3) should be [max-content\]]
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[hori-block-size-small-or-larger-than-container-with-min-or-max-content-1.html]
|
||||
expected: FAIL
|
|
@ -0,0 +1,2 @@
|
|||
[vert-block-size-small-or-larger-than-container-with-min-or-max-content-2a.html]
|
||||
expected: FAIL
|
148
tests/wpt/tests/css/css-sizing/keyword-sizes-on-inline-block.html
vendored
Normal file
148
tests/wpt/tests/css/css-sizing/keyword-sizes-on-inline-block.html
vendored
Normal file
|
@ -0,0 +1,148 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Keyword sizes on floated element</title>
|
||||
<link rel="author" title="Oriol Brufau" href="obrufau@igalia.com">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#sizing-values">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#sizing-values">
|
||||
<link rel="help" href="https://drafts.csswg.org/css2/#value-def-inline-block">
|
||||
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/11006">
|
||||
<meta assert="The various keyword sizes work as expected on inline-blocks.">
|
||||
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
|
||||
|
||||
<style>
|
||||
.wrapper {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-right: 150px;
|
||||
}
|
||||
|
||||
.test {
|
||||
display: inline-block;
|
||||
margin: 5px;
|
||||
border: 3px solid;
|
||||
padding: 2px;
|
||||
font: 20px/1 Ahem;
|
||||
}
|
||||
|
||||
/* Set the preferred size to small amount, to test that the min size works */
|
||||
.test.min-width { width: 0px }
|
||||
.test.min-height { height: 0px }
|
||||
|
||||
/* Set the preferred size to big amount, to test that the max size works */
|
||||
.test.max-width { width: 500px }
|
||||
.test.max-height { height: 500px }
|
||||
|
||||
/* stretch isn't widely supported, fall back to vendor-prefixed alternatives */
|
||||
.width.stretch { width: -moz-available; width: -webkit-fill-available; width: stretch }
|
||||
.min-width.stretch { min-width: -moz-available; min-width: -webkit-fill-available; min-width: stretch }
|
||||
.max-width.stretch { max-width: -moz-available; max-width: -webkit-fill-available; max-width: stretch }
|
||||
.height.stretch { height: -moz-available; height: -webkit-fill-available; height: stretch }
|
||||
.min-height.stretch { min-height: -moz-available; min-height: -webkit-fill-available; min-height: stretch }
|
||||
.max-height.stretch { max-height: -moz-available; max-height: -webkit-fill-available; max-height: stretch }
|
||||
</style>
|
||||
<div id="log"></div>
|
||||
|
||||
<!-- Intrinsic keywords -->
|
||||
<div class="wrapper" style="width: 100px; height: 100px">
|
||||
<div class="test width" style="width: min-content" data-expected-width="30">X X</div>
|
||||
<div class="test width" style="width: fit-content" data-expected-width="70">X X</div>
|
||||
<div class="test width" style="width: max-content" data-expected-width="70">X X</div>
|
||||
|
||||
<div class="test width" style="width: min-content" data-expected-width="70">XXX XXX</div>
|
||||
<div class="test width" style="width: fit-content" data-expected-width="90">XXX XXX</div>
|
||||
<div class="test width" style="width: max-content" data-expected-width="150">XXX XXX</div>
|
||||
|
||||
<div class="test width" style="width: min-content" data-expected-width="110">XXXXX XXXXX</div>
|
||||
<div class="test width" style="width: fit-content" data-expected-width="110">XXXXX XXXXX</div>
|
||||
<div class="test width" style="width: max-content" data-expected-width="230">XXXXX XXXXX</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="test min-width" style="min-width: min-content" data-expected-width="30">X X</div>
|
||||
<div class="test min-width" style="min-width: fit-content" data-expected-width="70">X X</div>
|
||||
<div class="test min-width" style="min-width: max-content" data-expected-width="70">X X</div>
|
||||
|
||||
<div class="test min-width" style="min-width: min-content" data-expected-width="70">XXX XXX</div>
|
||||
<div class="test min-width" style="min-width: fit-content" data-expected-width="90">XXX XXX</div>
|
||||
<div class="test min-width" style="min-width: max-content" data-expected-width="150">XXX XXX</div>
|
||||
|
||||
<div class="test min-width" style="min-width: min-content" data-expected-width="110">XXXXX XXXXX</div>
|
||||
<div class="test min-width" style="min-width: fit-content" data-expected-width="110">XXXXX XXXXX</div>
|
||||
<div class="test min-width" style="min-width: max-content" data-expected-width="230">XXXXX XXXXX</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="test max-width" style="max-width: min-content" data-expected-width="30">X X</div>
|
||||
<div class="test max-width" style="max-width: fit-content" data-expected-width="70">X X</div>
|
||||
<div class="test max-width" style="max-width: max-content" data-expected-width="70">X X</div>
|
||||
|
||||
<div class="test max-width" style="max-width: min-content" data-expected-width="70">XXX XXX</div>
|
||||
<div class="test max-width" style="max-width: fit-content" data-expected-width="90">XXX XXX</div>
|
||||
<div class="test max-width" style="max-width: max-content" data-expected-width="150">XXX XXX</div>
|
||||
|
||||
<div class="test max-width" style="max-width: min-content" data-expected-width="110">XXXXX XXXXX</div>
|
||||
<div class="test max-width" style="max-width: fit-content" data-expected-width="110">XXXXX XXXXX</div>
|
||||
<div class="test max-width" style="max-width: max-content" data-expected-width="230">XXXXX XXXXX</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="test height" style="height: min-content" data-expected-height="30">X X</div>
|
||||
<div class="test height" style="height: fit-content" data-expected-height="30">X X</div>
|
||||
<div class="test height" style="height: max-content" data-expected-height="30">X X</div>
|
||||
|
||||
<div class="test min-height" style="min-height: min-content" data-expected-height="30">X X</div>
|
||||
<div class="test min-height" style="min-height: fit-content" data-expected-height="30">X X</div>
|
||||
<div class="test min-height" style="min-height: max-content" data-expected-height="30">X X</div>
|
||||
|
||||
<div class="test max-height" style="max-height: min-content" data-expected-height="30">X X</div>
|
||||
<div class="test max-height" style="max-height: fit-content" data-expected-height="30">X X</div>
|
||||
<div class="test max-height" style="max-height: max-content" data-expected-height="30">X X</div>
|
||||
</div>
|
||||
|
||||
<!-- Definite stretch -->
|
||||
<div class="wrapper" style="width: 100px; height: 100px">
|
||||
<div class="test width stretch" data-expected-width="90">X X</div>
|
||||
<div class="test width stretch" data-expected-width="90">XXX XXX</div>
|
||||
<div class="test width stretch" data-expected-width="90">XXXXX XXXXX</div>
|
||||
|
||||
<div class="test min-width stretch" data-expected-width="90">X X</div>
|
||||
<div class="test min-width stretch" data-expected-width="90">XXX XXX</div>
|
||||
<div class="test min-width stretch" data-expected-width="90">XXXXX XXXXX</div>
|
||||
|
||||
<div class="test max-width stretch" data-expected-width="90">X X</div>
|
||||
<div class="test max-width stretch" data-expected-width="90">XXX XXX</div>
|
||||
<div class="test max-width stretch" data-expected-width="90">XXXXX XXXXX</div>
|
||||
|
||||
<div class="test height stretch" data-expected-height="90">X X</div>
|
||||
<div class="test height stretch" data-expected-height="90">XXX XXX<</div>
|
||||
<div class="test height stretch" data-expected-height="90">XXXXX XXXXX</div>
|
||||
|
||||
<div class="test min-height stretch" data-expected-height="90">X X</div>
|
||||
<div class="test min-height stretch" data-expected-height="90">XXX XXX</div>
|
||||
<div class="test min-height stretch" data-expected-height="90">XXXXX XXXXX</div>
|
||||
|
||||
<div class="test max-height stretch" data-expected-height="90">X X</div>
|
||||
<div class="test max-height stretch" data-expected-height="90">XXX XXX</div>
|
||||
<div class="test max-height stretch" data-expected-height="90">XXXXX XXXXX</div>
|
||||
</div>
|
||||
|
||||
<!-- Indefinite stretch -->
|
||||
<div class="wrapper" style="width: 100px; max-height: 100px">
|
||||
<div class="test height stretch indefinite" data-expected-height="30">X X</div>
|
||||
<div class="test height stretch indefinite" data-expected-height="50">XXX XXX</div>
|
||||
<div class="test height stretch indefinite" data-expected-height="50">XXXXX XXXXX</div>
|
||||
|
||||
<div class="test min-height stretch indefinite" data-expected-height="30">X X</div>
|
||||
<div class="test min-height stretch indefinite" data-expected-height="50">XXX XXX</div>
|
||||
<div class="test min-height stretch indefinite" data-expected-height="50">XXXXX XXXXX</div>
|
||||
|
||||
<div class="test max-height stretch indefinite" data-expected-height="30">X X</div>
|
||||
<div class="test max-height stretch indefinite" data-expected-height="50">XXX XXX</div>
|
||||
<div class="test max-height stretch indefinite" data-expected-height="50">XXXXX XXXXX</div>
|
||||
</div>
|
||||
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/resources/check-layout-th.js"></script>
|
||||
<script>
|
||||
checkLayout(".test");
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue