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) {
(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(
const LayoutObject& dialog,
LayoutUnit height) {
......@@ -406,6 +425,9 @@ void ComputeOutOfFlowInlineDimensions(
min_max_sizes, style.LogicalWidth());
} else if (replaced_size.has_value()) {
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(
......
......@@ -55,6 +55,10 @@ CORE_EXPORT bool AbsoluteNeedsChildInlineSize(const ComputedStyle&);
// block-size.
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
// inline-size.
// |replaced_size| should be set if and only if element is replaced element.
......
......@@ -29,6 +29,7 @@ class NGAbsoluteUtilsTest : public testing::Test {
void SetUp() override {
style_ = ComputedStyle::Create();
style_->SetPosition(EPosition::kAbsolute);
// If not set, border widths will always be 0.
style_->SetBorderLeftStyle(EBorderStyle::kSolid);
style_->SetBorderRightStyle(EBorderStyle::kSolid);
......
......@@ -730,12 +730,19 @@ MinMaxSizesResult NGBlockNode::ComputeMinMaxSizes(
constraint_space = &zero_constraint_space;
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 =
CalculateInitialMinMaxFragmentGeometry(*constraint_space, *this);
NGBoxStrut border_padding =
fragment_geometry.border + fragment_geometry.padding;
LayoutUnit size_from_ar = ComputeInlineSizeFromAspectRatio(
*constraint_space, Style(), border_padding);
*constraint_space, Style(), border_padding, block_size);
if (size_from_ar != kIndefiniteSize) {
return {{size_from_ar, size_from_ar},
Style().LogicalHeight().IsPercentOrCalc()};
......
......@@ -225,8 +225,6 @@ LayoutUnit ResolveBlockLengthInternal(
}
}
namespace {
LayoutUnit InlineSizeFromAspectRatio(const NGBoxStrut& border_padding,
const LogicalSize& aspect_ratio,
EBoxSizing box_sizing,
......@@ -251,6 +249,8 @@ LayoutUnit BlockSizeFromAspectRatio(const NGBoxStrut& border_padding,
border_padding.BlockSum();
}
namespace {
template <typename MinMaxSizesFunc>
MinMaxSizesResult ComputeMinAndMaxContentContributionInternal(
WritingMode parent_writing_mode,
......@@ -401,18 +401,21 @@ MinMaxSizesResult ComputeMinAndMaxContentContribution(
LayoutUnit ComputeInlineSizeFromAspectRatio(const NGConstraintSpace& space,
const ComputedStyle& style,
const NGBoxStrut& border_padding) {
if (UNLIKELY(style.LogicalAspectRatio() && !style.LogicalHeight().IsAuto())) {
// Check if we can get an inline size using the aspect ratio
LayoutUnit block_size = ComputeBlockSizeForFragment(
space, style, border_padding, kIndefiniteSize, base::nullopt);
if (block_size != kIndefiniteSize) {
return InlineSizeFromAspectRatio(border_padding,
*style.LogicalAspectRatio(),
style.BoxSizing(), block_size);
}
const NGBoxStrut& border_padding,
LayoutUnit block_size) {
if (LIKELY(!style.AspectRatio()))
return kIndefiniteSize;
if (!style.LogicalHeight().IsAuto() && block_size == kIndefiniteSize) {
DCHECK(!style.HasOutOfFlowPosition()) << "OOF should pass in a block size";
block_size = ComputeBlockSizeForFragment(space, style, border_padding,
kIndefiniteSize, base::nullopt);
}
return kIndefiniteSize;
if (block_size == 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(
......
......@@ -41,6 +41,16 @@ inline bool NeedMinMaxSize(const ComputedStyle& style) {
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
// during the intrinsic phase. For block lengths we also consider 'auto',
// 'min-content', 'max-content', 'fit-content' and 'none' (for max-block-size)
......@@ -311,9 +321,13 @@ MinMaxSizes ComputeMinMaxBlockSize(
// 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,
// returns kIndefiniteSize.
LayoutUnit ComputeInlineSizeFromAspectRatio(const NGConstraintSpace&,
const ComputedStyle&,
const NGBoxStrut& border_padding);
// block_size can be specified to base the calculation off of that size
// instead of calculating it.
LayoutUnit ComputeInlineSizeFromAspectRatio(
const NGConstraintSpace&,
const ComputedStyle&,
const NGBoxStrut& border_padding,
LayoutUnit block_size = kIndefiniteSize);
// 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,
......
......@@ -730,8 +730,12 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
bool absolute_needs_child_block_size =
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) ||
NeedMinMaxSize(candidate_style) || should_be_considered_as_replaced) {
NeedMinMaxSize(candidate_style) || should_be_considered_as_replaced ||
IsInlineSizeComputableFromBlockSize(candidate_style)) {
MinMaxSizesInput input(kIndefiniteSize, MinMaxSizesType::kContent);
if (is_replaced) {
input.percentage_resolution_block_size =
......@@ -753,14 +757,13 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
}
base::Optional<LogicalSize> replaced_size;
base::Optional<LogicalSize> replaced_aspect_ratio;
base::Optional<LogicalSize> aspect_ratio;
bool has_aspect_ratio_without_intrinsic_size = false;
if (is_replaced) {
ComputeReplacedSize(node, candidate_constraint_space, min_max_sizes,
&replaced_size, &replaced_aspect_ratio);
has_aspect_ratio_without_intrinsic_size = !replaced_size &&
replaced_aspect_ratio &&
!replaced_aspect_ratio->IsEmpty();
&replaced_size, &aspect_ratio);
has_aspect_ratio_without_intrinsic_size =
!replaced_size && aspect_ratio && !aspect_ratio->IsEmpty();
// If we only have aspect ratio, and no replaced size, 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
......@@ -768,6 +771,9 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
// https://www.w3.org/TR/CSS22/visudet.html#inline-replaced-width
if (has_aspect_ratio_without_intrinsic_size)
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) {
replaced_size =
LogicalSize{min_max_sizes->ShrinkToFit(
......@@ -789,12 +795,15 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
// inline size and aspect ratio.
// https://www.w3.org/TR/css-sizing-3/#intrinsic-sizes
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(
node_dimensions.size.inline_size,
(replaced_aspect_ratio->block_size *
((node_dimensions.size.inline_size - border_padding.InlineSum()) /
replaced_aspect_ratio->inline_size)) +
border_padding.BlockSum());
BlockSizeFromAspectRatio(border_padding, *aspect_ratio, sizing,
node_dimensions.size.inline_size));
}
if (absolute_needs_child_block_size) {
DCHECK(!has_computed_block_dimensions);
......
......@@ -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-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-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/block-aspect-ratio-001.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
# not implemented yet
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 ]
# 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.
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