Commit 2f841852 authored by Christian Biesinger's avatar Christian Biesinger Committed by Commit Bot

[AspectRatio] Support aspect-ratio for out-of-flow boxes

R=ikilpatrick@chromium.org

Bug: 1098475
Change-Id: Ibe99426f1737841957b7f6611bcab70228724786
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2261875
Commit-Queue: Christian Biesinger <cbiesinger@chromium.org>
Auto-Submit: Christian Biesinger <cbiesinger@chromium.org>
Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#789267}
parent fae5e7f8
...@@ -338,6 +338,25 @@ bool AbsoluteNeedsChildBlockSize(const ComputedStyle& style) { ...@@ -338,6 +338,25 @@ bool AbsoluteNeedsChildBlockSize(const ComputedStyle& style) {
(style.LogicalTop().IsAuto() || style.LogicalBottom().IsAuto())); (style.LogicalTop().IsAuto() || style.LogicalBottom().IsAuto()));
} }
bool IsInlineSizeComputableFromBlockSize(const ComputedStyle& style) {
DCHECK(style.HasOutOfFlowPosition());
if (!style.AspectRatio())
return false;
// An explicit block size should take precedence over specified insets.
bool have_inline_size =
style.LogicalWidth().IsFixed() || style.LogicalWidth().IsPercentOrCalc();
bool have_block_size = style.LogicalHeight().IsFixed() ||
style.LogicalHeight().IsPercentOrCalc();
if (have_inline_size)
return false;
if (have_block_size)
return true;
// If we have block insets but no inline insets, we compute based on the
// insets.
return !AbsoluteNeedsChildBlockSize(style) &&
AbsoluteNeedsChildInlineSize(style);
}
base::Optional<LayoutUnit> ComputeAbsoluteDialogYPosition( base::Optional<LayoutUnit> ComputeAbsoluteDialogYPosition(
const LayoutObject& dialog, const LayoutObject& dialog,
LayoutUnit height) { LayoutUnit height) {
...@@ -406,6 +425,9 @@ void ComputeOutOfFlowInlineDimensions( ...@@ -406,6 +425,9 @@ void ComputeOutOfFlowInlineDimensions(
min_max_sizes, style.LogicalWidth()); min_max_sizes, style.LogicalWidth());
} else if (replaced_size.has_value()) { } else if (replaced_size.has_value()) {
inline_size = replaced_size->inline_size; inline_size = replaced_size->inline_size;
} else if (IsInlineSizeComputableFromBlockSize(style)) {
DCHECK(min_max_sizes.has_value());
inline_size = min_max_sizes->min_size;
} }
LayoutUnit min_inline_size = ResolveMinInlineLength( LayoutUnit min_inline_size = ResolveMinInlineLength(
......
...@@ -55,6 +55,10 @@ CORE_EXPORT bool AbsoluteNeedsChildInlineSize(const ComputedStyle&); ...@@ -55,6 +55,10 @@ CORE_EXPORT bool AbsoluteNeedsChildInlineSize(const ComputedStyle&);
// block-size. // block-size.
CORE_EXPORT bool AbsoluteNeedsChildBlockSize(const ComputedStyle&); CORE_EXPORT bool AbsoluteNeedsChildBlockSize(const ComputedStyle&);
// Returns true if the inline size can be computed from an aspect ratio and
// the block size.
bool IsInlineSizeComputableFromBlockSize(const ComputedStyle& style);
// Computes part of the absolute position which depends on the child's // Computes part of the absolute position which depends on the child's
// inline-size. // inline-size.
// |replaced_size| should be set if and only if element is replaced element. // |replaced_size| should be set if and only if element is replaced element.
......
...@@ -29,6 +29,7 @@ class NGAbsoluteUtilsTest : public testing::Test { ...@@ -29,6 +29,7 @@ class NGAbsoluteUtilsTest : public testing::Test {
void SetUp() override { void SetUp() override {
style_ = ComputedStyle::Create(); style_ = ComputedStyle::Create();
style_->SetPosition(EPosition::kAbsolute);
// If not set, border widths will always be 0. // If not set, border widths will always be 0.
style_->SetBorderLeftStyle(EBorderStyle::kSolid); style_->SetBorderLeftStyle(EBorderStyle::kSolid);
style_->SetBorderRightStyle(EBorderStyle::kSolid); style_->SetBorderRightStyle(EBorderStyle::kSolid);
......
...@@ -730,12 +730,19 @@ MinMaxSizesResult NGBlockNode::ComputeMinMaxSizes( ...@@ -730,12 +730,19 @@ MinMaxSizesResult NGBlockNode::ComputeMinMaxSizes(
constraint_space = &zero_constraint_space; constraint_space = &zero_constraint_space;
if (Style().AspectRatio() && input.type == MinMaxSizesType::kContent) { if (Style().AspectRatio() && input.type == MinMaxSizesType::kContent) {
LayoutUnit block_size(kIndefiniteSize);
if (IsOutOfFlowPositioned()) {
// For out-of-flow, the input percentage block size is actually our
// block size. We should use that for aspect-ratio purposes if known.
block_size = input.percentage_resolution_block_size;
}
NGFragmentGeometry fragment_geometry = NGFragmentGeometry fragment_geometry =
CalculateInitialMinMaxFragmentGeometry(*constraint_space, *this); CalculateInitialMinMaxFragmentGeometry(*constraint_space, *this);
NGBoxStrut border_padding = NGBoxStrut border_padding =
fragment_geometry.border + fragment_geometry.padding; fragment_geometry.border + fragment_geometry.padding;
LayoutUnit size_from_ar = ComputeInlineSizeFromAspectRatio( LayoutUnit size_from_ar = ComputeInlineSizeFromAspectRatio(
*constraint_space, Style(), border_padding); *constraint_space, Style(), border_padding, block_size);
if (size_from_ar != kIndefiniteSize) { if (size_from_ar != kIndefiniteSize) {
return {{size_from_ar, size_from_ar}, return {{size_from_ar, size_from_ar},
Style().LogicalHeight().IsPercentOrCalc()}; Style().LogicalHeight().IsPercentOrCalc()};
......
...@@ -225,8 +225,6 @@ LayoutUnit ResolveBlockLengthInternal( ...@@ -225,8 +225,6 @@ LayoutUnit ResolveBlockLengthInternal(
} }
} }
namespace {
LayoutUnit InlineSizeFromAspectRatio(const NGBoxStrut& border_padding, LayoutUnit InlineSizeFromAspectRatio(const NGBoxStrut& border_padding,
const LogicalSize& aspect_ratio, const LogicalSize& aspect_ratio,
EBoxSizing box_sizing, EBoxSizing box_sizing,
...@@ -251,6 +249,8 @@ LayoutUnit BlockSizeFromAspectRatio(const NGBoxStrut& border_padding, ...@@ -251,6 +249,8 @@ LayoutUnit BlockSizeFromAspectRatio(const NGBoxStrut& border_padding,
border_padding.BlockSum(); border_padding.BlockSum();
} }
namespace {
template <typename MinMaxSizesFunc> template <typename MinMaxSizesFunc>
MinMaxSizesResult ComputeMinAndMaxContentContributionInternal( MinMaxSizesResult ComputeMinAndMaxContentContributionInternal(
WritingMode parent_writing_mode, WritingMode parent_writing_mode,
...@@ -401,18 +401,21 @@ MinMaxSizesResult ComputeMinAndMaxContentContribution( ...@@ -401,18 +401,21 @@ MinMaxSizesResult ComputeMinAndMaxContentContribution(
LayoutUnit ComputeInlineSizeFromAspectRatio(const NGConstraintSpace& space, LayoutUnit ComputeInlineSizeFromAspectRatio(const NGConstraintSpace& space,
const ComputedStyle& style, const ComputedStyle& style,
const NGBoxStrut& border_padding) { const NGBoxStrut& border_padding,
if (UNLIKELY(style.LogicalAspectRatio() && !style.LogicalHeight().IsAuto())) { LayoutUnit block_size) {
// Check if we can get an inline size using the aspect ratio if (LIKELY(!style.AspectRatio()))
LayoutUnit block_size = ComputeBlockSizeForFragment( return kIndefiniteSize;
space, style, border_padding, kIndefiniteSize, base::nullopt);
if (block_size != kIndefiniteSize) { if (!style.LogicalHeight().IsAuto() && block_size == kIndefiniteSize) {
return InlineSizeFromAspectRatio(border_padding, DCHECK(!style.HasOutOfFlowPosition()) << "OOF should pass in a block size";
*style.LogicalAspectRatio(), block_size = ComputeBlockSizeForFragment(space, style, border_padding,
style.BoxSizing(), block_size); kIndefiniteSize, base::nullopt);
}
} }
if (block_size == kIndefiniteSize)
return kIndefiniteSize; return kIndefiniteSize;
// Check if we can get an inline size using the aspect ratio.
return InlineSizeFromAspectRatio(border_padding, *style.LogicalAspectRatio(),
style.BoxSizing(), block_size);
} }
LayoutUnit ComputeInlineSizeForFragment( LayoutUnit ComputeInlineSizeForFragment(
......
...@@ -41,6 +41,16 @@ inline bool NeedMinMaxSize(const ComputedStyle& style) { ...@@ -41,6 +41,16 @@ inline bool NeedMinMaxSize(const ComputedStyle& style) {
style.LogicalMaxWidth().IsIntrinsic(); style.LogicalMaxWidth().IsIntrinsic();
} }
LayoutUnit InlineSizeFromAspectRatio(const NGBoxStrut& border_padding,
const LogicalSize& aspect_ratio,
EBoxSizing box_sizing,
LayoutUnit block_size);
LayoutUnit BlockSizeFromAspectRatio(const NGBoxStrut& border_padding,
const LogicalSize& aspect_ratio,
EBoxSizing box_sizing,
LayoutUnit inline_size);
// Returns if the given |Length| is unresolvable, e.g. the length is %-based // Returns if the given |Length| is unresolvable, e.g. the length is %-based
// during the intrinsic phase. For block lengths we also consider 'auto', // during the intrinsic phase. For block lengths we also consider 'auto',
// 'min-content', 'max-content', 'fit-content' and 'none' (for max-block-size) // 'min-content', 'max-content', 'fit-content' and 'none' (for max-block-size)
...@@ -311,9 +321,13 @@ MinMaxSizes ComputeMinMaxBlockSize( ...@@ -311,9 +321,13 @@ MinMaxSizes ComputeMinMaxBlockSize(
// Tries to compute the inline size of a node from its block size and // Tries to compute the inline size of a node from its block size and
// aspect ratio. If there is no aspect ratio or the block size is indefinite, // aspect ratio. If there is no aspect ratio or the block size is indefinite,
// returns kIndefiniteSize. // returns kIndefiniteSize.
LayoutUnit ComputeInlineSizeFromAspectRatio(const NGConstraintSpace&, // block_size can be specified to base the calculation off of that size
// instead of calculating it.
LayoutUnit ComputeInlineSizeFromAspectRatio(
const NGConstraintSpace&,
const ComputedStyle&, const ComputedStyle&,
const NGBoxStrut& border_padding); const NGBoxStrut& border_padding,
LayoutUnit block_size = kIndefiniteSize);
// Returns inline size of the node's border box by resolving the computed value // Returns inline size of the node's border box by resolving the computed value
// in style.logicalWidth (Length) to a layout unit, adding border and padding, // in style.logicalWidth (Length) to a layout unit, adding border and padding,
......
...@@ -730,8 +730,12 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout( ...@@ -730,8 +730,12 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
bool absolute_needs_child_block_size = bool absolute_needs_child_block_size =
AbsoluteNeedsChildBlockSize(candidate_style); AbsoluteNeedsChildBlockSize(candidate_style);
// We also include items with aspect ratio here, because if the inline size
// is auto and we have a definite block size, we want to use that for the
// inline size calculation.
if (AbsoluteNeedsChildInlineSize(candidate_style) || if (AbsoluteNeedsChildInlineSize(candidate_style) ||
NeedMinMaxSize(candidate_style) || should_be_considered_as_replaced) { NeedMinMaxSize(candidate_style) || should_be_considered_as_replaced ||
IsInlineSizeComputableFromBlockSize(candidate_style)) {
MinMaxSizesInput input(kIndefiniteSize, MinMaxSizesType::kContent); MinMaxSizesInput input(kIndefiniteSize, MinMaxSizesType::kContent);
if (is_replaced) { if (is_replaced) {
input.percentage_resolution_block_size = input.percentage_resolution_block_size =
...@@ -753,14 +757,13 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout( ...@@ -753,14 +757,13 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
} }
base::Optional<LogicalSize> replaced_size; base::Optional<LogicalSize> replaced_size;
base::Optional<LogicalSize> replaced_aspect_ratio; base::Optional<LogicalSize> aspect_ratio;
bool has_aspect_ratio_without_intrinsic_size = false; bool has_aspect_ratio_without_intrinsic_size = false;
if (is_replaced) { if (is_replaced) {
ComputeReplacedSize(node, candidate_constraint_space, min_max_sizes, ComputeReplacedSize(node, candidate_constraint_space, min_max_sizes,
&replaced_size, &replaced_aspect_ratio); &replaced_size, &aspect_ratio);
has_aspect_ratio_without_intrinsic_size = !replaced_size && has_aspect_ratio_without_intrinsic_size =
replaced_aspect_ratio && !replaced_size && aspect_ratio && !aspect_ratio->IsEmpty();
!replaced_aspect_ratio->IsEmpty();
// If we only have aspect ratio, and no replaced size, intrinsic size // If we only have aspect ratio, and no replaced size, intrinsic size
// defaults to 300x150. min_max_sizes gets computed from the intrinsic size. // defaults to 300x150. min_max_sizes gets computed from the intrinsic size.
// We reset the min_max_sizes because spec says that OOF-positioned size // We reset the min_max_sizes because spec says that OOF-positioned size
...@@ -768,6 +771,9 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout( ...@@ -768,6 +771,9 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
// https://www.w3.org/TR/CSS22/visudet.html#inline-replaced-width // https://www.w3.org/TR/CSS22/visudet.html#inline-replaced-width
if (has_aspect_ratio_without_intrinsic_size) if (has_aspect_ratio_without_intrinsic_size)
min_max_sizes = MinMaxSizes{LayoutUnit(), LayoutUnit::NearlyMax()}; min_max_sizes = MinMaxSizes{LayoutUnit(), LayoutUnit::NearlyMax()};
} else if (candidate_style.AspectRatio()) {
has_aspect_ratio_without_intrinsic_size = true;
aspect_ratio = node.GetAspectRatio();
} else if (should_be_considered_as_replaced) { } else if (should_be_considered_as_replaced) {
replaced_size = replaced_size =
LogicalSize{min_max_sizes->ShrinkToFit( LogicalSize{min_max_sizes->ShrinkToFit(
...@@ -789,12 +795,15 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout( ...@@ -789,12 +795,15 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
// inline size and aspect ratio. // inline size and aspect ratio.
// https://www.w3.org/TR/css-sizing-3/#intrinsic-sizes // https://www.w3.org/TR/css-sizing-3/#intrinsic-sizes
if (has_aspect_ratio_without_intrinsic_size) { if (has_aspect_ratio_without_intrinsic_size) {
// If this came from an aspect-ratio property, we need to respect
// box-sizing.
EBoxSizing sizing = candidate_style.AspectRatio()
? candidate_style.BoxSizing()
: EBoxSizing::kContentBox;
replaced_size = LogicalSize( replaced_size = LogicalSize(
node_dimensions.size.inline_size, node_dimensions.size.inline_size,
(replaced_aspect_ratio->block_size * BlockSizeFromAspectRatio(border_padding, *aspect_ratio, sizing,
((node_dimensions.size.inline_size - border_padding.InlineSum()) / node_dimensions.size.inline_size));
replaced_aspect_ratio->inline_size)) +
border_padding.BlockSum());
} }
if (absolute_needs_child_block_size) { if (absolute_needs_child_block_size) {
DCHECK(!has_computed_block_dimensions); DCHECK(!has_computed_block_dimensions);
......
...@@ -98,6 +98,9 @@ crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-005.tentative. ...@@ -98,6 +98,9 @@ crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-005.tentative.
crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-006.tentative.html [ Failure ] crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-006.tentative.html [ Failure ]
crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-007.tentative.html [ Failure ] crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-007.tentative.html [ Failure ]
crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-008.tentative.html [ Failure ] crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-008.tentative.html [ Failure ]
crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-009.tentative.html [ Failure ]
crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-010.tentative.html [ Failure ]
crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-011.tentative.html [ Failure ]
crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/auto-margins-001.tentative.html [ Failure ] crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/auto-margins-001.tentative.html [ Failure ]
crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/block-aspect-ratio-001.tentative.html [ Failure ] crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/block-aspect-ratio-001.tentative.html [ Failure ]
crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/block-aspect-ratio-002.tentative.html [ Failure ] crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/block-aspect-ratio-002.tentative.html [ Failure ]
......
...@@ -262,16 +262,8 @@ crbug.com/1007229 external/wpt/intersection-observer/same-origin-grand-child-ifr ...@@ -262,16 +262,8 @@ crbug.com/1007229 external/wpt/intersection-observer/same-origin-grand-child-ifr
# not implemented yet # not implemented yet
crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/block-aspect-ratio-020.tentative.html [ Failure ] crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/block-aspect-ratio-020.tentative.html [ Failure ]
# abspos is not implemented yet for aspect-ratio
crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-003.tentative.html [ Failure ]
crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-005.tentative.html [ Failure ]
crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-006.tentative.html [ Failure ]
crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-008.tentative.html [ Failure ] crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-008.tentative.html [ Failure ]
# It is not clear if this test is correct. https://github.com/w3c/csswg-drafts/issues/5151
crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-004.tentative.html [ Failure ]
# Incorrect blending with foreignObject and svg descendants. # Incorrect blending with foreignObject and svg descendants.
crbug.com/1102803 external/wpt/svg/extensibility/foreignObject/isolation-with-svg.html [ Failure ] crbug.com/1102803 external/wpt/svg/extensibility/foreignObject/isolation-with-svg.html [ Failure ]
......
<!DOCTYPE html>
<title>CSS aspect-ratio: abspos div inline size with percentage height</title>
<link rel="author" title="Google LLC" href="https://www.google.com/">
<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#aspect-ratio">
<link rel="match" href="../../reference/ref-filled-green-100px-square.xht" />
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div style="width: 500px; position: relative;">
<div style="background: green; aspect-ratio: 1/1; height: 100%; position: absolute; left: 0; right: 0; top: 0; bottom: 0;"></div>
<div style="height: 100px"></div> <!-- for sizing the abspos containing block -->
</div>
<!DOCTYPE html>
<title>CSS aspect-ratio: out-of-flow div block size with box-sizing</title>
<link rel="author" title="Google LLC" href="https://www.google.com/">
<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#aspect-ratio">
<link rel="match" href="../../reference/ref-filled-green-100px-square.xht" />
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div style="background: green; width: 100px; padding: 10px 20px 30px 40px; aspect-ratio: 1/1; position: absolute; box-sizing: border-box;"></div>
<!DOCTYPE html>
<title>CSS aspect-ratio: out-of-flow div block size with box-sizing</title>
<link rel="author" title="Google LLC" href="https://www.google.com/">
<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#aspect-ratio">
<link rel="match" href="../../reference/ref-filled-green-100px-square.xht" />
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div style="background: green; width: 80px; padding: 0px 5px 0px 15px; aspect-ratio: 1/1; position: absolute; box-sizing: content-box;"></div>
<div style="height: 80px;"></div>
<div style="background: green; width: 100px; height: 20px;"></div>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment