Commit 2193d880 authored by Morten Stenshorne's avatar Morten Stenshorne Committed by Commit Bot

[LayoutNG] Get rid of extrinsic constraint space.

The extrinsic constraint space was used to calculate the intrinsic
min/max sizes of orthogonal roots.  However, now that our orthogonal
flow fallback available inline size calculation is good enough, we no
longer need the concept of "extrinsic constraint space". Instead create
one with infinite sizes, but with correct fallback inline size. One
change is required, though: We need to honor fixed block-size (and not
just block-max-size and block-min-size) when calculating the fallback
size. During layout, that size is already taken care of and put in the
constraint space, but during intrinsic sizing, that isn't the case.

Create the infinite constraint space in
ComputeMinAndMaxContentContribution(), rather than at all call sites.
Make the NGConstraintSpace parameter non-optional, and make it clear
that it's the parent constraint space we take as input; previously it
was sometimes the child's and sometimes the parent's.

Change-Id: I7c884e383266c67bfa9438e98ad1312b39ea9372
Reviewed-on: https://chromium-review.googlesource.com/c/1341513
Commit-Queue: Morten Stenshorne <mstensho@chromium.org>
Reviewed-by: default avatarChristian Biesinger <cbiesinger@chromium.org>
Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#610117}
parent c7b82973
...@@ -922,20 +922,8 @@ static LayoutUnit ComputeContentSize( ...@@ -922,20 +922,8 @@ static LayoutUnit ComputeContentSize(
const ComputedStyle& float_style = float_node.Style(); const ComputedStyle& float_style = float_node.Style();
MinMaxSizeInput zero_input; // Floats don't intrude into floats. MinMaxSizeInput zero_input; // Floats don't intrude into floats.
// We'll need extrinsic sizing data when computing min/max for orthogonal MinMaxSize child_sizes =
// flow roots. ComputeMinAndMaxContentContribution(style, float_node, zero_input);
NGConstraintSpace extrinsic_constraint_space;
const NGConstraintSpace* optional_constraint_space = nullptr;
if (!IsParallelWritingMode(container_writing_mode,
float_node.Style().GetWritingMode())) {
DCHECK(constraint_space);
extrinsic_constraint_space = CreateExtrinsicConstraintSpaceForChild(
*constraint_space, style, input.extrinsic_block_size, float_node);
optional_constraint_space = &extrinsic_constraint_space;
}
MinMaxSize child_sizes = ComputeMinAndMaxContentContribution(
writing_mode, float_node, zero_input, optional_constraint_space);
LayoutUnit child_inline_margins = LayoutUnit child_inline_margins =
ComputeMinMaxMargins(style, float_node).InlineSum(); ComputeMinMaxMargins(style, float_node).InlineSum();
......
...@@ -806,11 +806,10 @@ void NGLineBreaker::HandleAtomicInline(const NGInlineItem& item) { ...@@ -806,11 +806,10 @@ void NGLineBreaker::HandleAtomicInline(const NGInlineItem& item) {
*item_result->layout_result->PhysicalFragment()) *item_result->layout_result->PhysicalFragment())
.InlineSize(); .InlineSize();
} else { } else {
NGBlockNode block_node(ToLayoutBox(item.GetLayoutObject())); NGBlockNode child(ToLayoutBox(item.GetLayoutObject()));
MinMaxSizeInput input; MinMaxSizeInput input;
MinMaxSize sizes = ComputeMinAndMaxContentContribution( MinMaxSize sizes =
constraint_space_.GetWritingMode(), block_node, input, ComputeMinAndMaxContentContribution(node_.Style(), child, input);
&constraint_space_);
item_result->inline_size = mode_ == NGLineBreakerMode::kMinContent item_result->inline_size = mode_ == NGLineBreakerMode::kMinContent
? sizes.min_size ? sizes.min_size
: sizes.max_size; : sizes.max_size;
......
...@@ -200,14 +200,6 @@ base::Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize( ...@@ -200,14 +200,6 @@ base::Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize(
LayoutUnit float_left_inline_size = input.float_left_inline_size; LayoutUnit float_left_inline_size = input.float_left_inline_size;
LayoutUnit float_right_inline_size = input.float_right_inline_size; LayoutUnit float_right_inline_size = input.float_right_inline_size;
LayoutUnit extrinsic_block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), NGSizeIndefinite, border_padding);
if (extrinsic_block_size != NGSizeIndefinite) {
extrinsic_block_size -=
(border_padding + Node().GetScrollbarSizes()).BlockSum();
extrinsic_block_size = extrinsic_block_size.ClampNegativeToZero();
}
for (NGLayoutInputNode child = Node().FirstChild(); child; for (NGLayoutInputNode child = Node().FirstChild(); child;
child = child.NextSibling()) { child = child.NextSibling()) {
if (child.IsOutOfFlowPositioned() || child.IsColumnSpanAll()) if (child.IsOutOfFlowPositioned() || child.IsColumnSpanAll())
...@@ -238,10 +230,8 @@ base::Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize( ...@@ -238,10 +230,8 @@ base::Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize(
} }
MinMaxSizeInput child_input; MinMaxSizeInput child_input;
if (child.IsInline() || child.IsAnonymousBlock()) { if (child.IsInline() || child.IsAnonymousBlock())
child_input = {float_left_inline_size, float_right_inline_size, child_input = {float_left_inline_size, float_right_inline_size};
extrinsic_block_size};
}
MinMaxSize child_sizes; MinMaxSize child_sizes;
if (child.IsInline()) { if (child.IsInline()) {
...@@ -250,27 +240,12 @@ base::Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize( ...@@ -250,27 +240,12 @@ base::Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize(
// all inline nodes following |child| and their descendants, and produces // all inline nodes following |child| and their descendants, and produces
// an anonymous box that contains all line boxes. // an anonymous box that contains all line boxes.
// |NextSibling| returns the next block sibling, or nullptr, skipping all // |NextSibling| returns the next block sibling, or nullptr, skipping all
// following inline siblings and descendants. We'll pass our constraint // following inline siblings and descendants.
// space here, so that floated orthogonal flow roots can calculate an child_sizes =
// extrinsic constraint space. child.ComputeMinMaxSize(Style().GetWritingMode(), child_input);
child_sizes = child.ComputeMinMaxSize(Style().GetWritingMode(),
child_input, &constraint_space_);
} else { } else {
// We'll need extrinsic sizing data when computing min/max for orthogonal child_sizes =
// flow roots. If the child is a block node, we can check that right away, ComputeMinAndMaxContentContribution(Style(), child, child_input);
// but if it's inline, there's no way of telling; there may be floated
// children that establish an orthogonal flow root.
NGConstraintSpace extrinsic_constraint_space;
const NGConstraintSpace* optional_constraint_space = nullptr;
if (!IsParallelWritingMode(Style().GetWritingMode(),
child.Style().GetWritingMode())) {
extrinsic_constraint_space = CreateExtrinsicConstraintSpaceForChild(
ConstraintSpace(), Style(), extrinsic_block_size, child);
optional_constraint_space = &extrinsic_constraint_space;
}
child_sizes = ComputeMinAndMaxContentContribution(
Style().GetWritingMode(), child, child_input,
optional_constraint_space);
} }
DCHECK_LE(child_sizes.min_size, child_sizes.max_size) << child.ToString(); DCHECK_LE(child_sizes.min_size, child_sizes.max_size) << child.ToString();
......
...@@ -148,33 +148,7 @@ base::Optional<MinMaxSize> NGFieldsetLayoutAlgorithm::ComputeMinMaxSize( ...@@ -148,33 +148,7 @@ base::Optional<MinMaxSize> NGFieldsetLayoutAlgorithm::ComputeMinMaxSize(
return sizes; return sizes;
if (NGBlockNode legend = Node().GetRenderedLegend()) { if (NGBlockNode legend = Node().GetRenderedLegend()) {
// We'll need extrinsic sizing data when computing min/max for orthogonal sizes = ComputeMinAndMaxContentContribution(Style(), legend, input);
// flow roots, because calculating min/max in that case will involve doing
// layout. Note that we only need to do this for the legend, and not for the
// fieldset contents. The contents child is just an anonymous one, which
// inherits writing-mode from the fieldset, so it can never be a writing
// mode root.
NGConstraintSpace extrinsic_constraint_space;
const NGConstraintSpace* optional_constraint_space = nullptr;
if (!IsParallelWritingMode(Style().GetWritingMode(),
legend.Style().GetWritingMode())) {
NGBoxStrut border_padding = ComputeBorders(ConstraintSpace(), Node()) +
ComputePadding(ConstraintSpace(), Style());
// If there is a resolvable extrinsic block size, use that as input.
// Otherwise we'll fall back to the initial containing block size as a
// constraint.
LayoutUnit extrinsic_block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), NGSizeIndefinite, border_padding);
if (extrinsic_block_size != NGSizeIndefinite) {
extrinsic_block_size -= border_padding.BlockSum();
extrinsic_block_size = extrinsic_block_size.ClampNegativeToZero();
}
extrinsic_constraint_space = CreateExtrinsicConstraintSpaceForChild(
ConstraintSpace(), Style(), extrinsic_block_size, legend);
optional_constraint_space = &extrinsic_constraint_space;
}
sizes = ComputeMinAndMaxContentContribution(
Style().GetWritingMode(), legend, input, optional_constraint_space);
sizes += ComputeMinMaxMargins(Style(), legend).InlineSum(); sizes += ComputeMinMaxMargins(Style(), legend).InlineSum();
} }
// The fieldset content includes the fieldset padding (and any scrollbars), // The fieldset content includes the fieldset padding (and any scrollbars),
...@@ -183,8 +157,8 @@ base::Optional<MinMaxSize> NGFieldsetLayoutAlgorithm::ComputeMinMaxSize( ...@@ -183,8 +157,8 @@ base::Optional<MinMaxSize> NGFieldsetLayoutAlgorithm::ComputeMinMaxSize(
sizes += ComputePadding(ConstraintSpace(), node_.Style()).InlineSum(); sizes += ComputePadding(ConstraintSpace(), node_.Style()).InlineSum();
if (NGBlockNode content = Node().GetFieldsetContent()) { if (NGBlockNode content = Node().GetFieldsetContent()) {
MinMaxSize content_minmax = ComputeMinAndMaxContentContribution( MinMaxSize content_minmax =
Style().GetWritingMode(), content, input); ComputeMinAndMaxContentContribution(Style(), content, input);
content_minmax += ComputeMinMaxMargins(Style(), content).InlineSum(); content_minmax += ComputeMinMaxMargins(Style(), content).InlineSum();
sizes.Encompass(content_minmax); sizes.Encompass(content_minmax);
} }
......
...@@ -32,15 +32,11 @@ enum class NGMinMaxSizeType { kContentBoxSize, kBorderBoxSize }; ...@@ -32,15 +32,11 @@ enum class NGMinMaxSizeType { kContentBoxSize, kBorderBoxSize };
// Input to the min/max inline size calculation algorithm for child nodes. Child // Input to the min/max inline size calculation algorithm for child nodes. Child
// nodes within the same formatting context need to know which floats are beside // nodes within the same formatting context need to know which floats are beside
// them. Additionally, orthogonal writing mode roots will need the extrinsic // them.
// block-size of the container.
struct MinMaxSizeInput { struct MinMaxSizeInput {
LayoutUnit float_left_inline_size; LayoutUnit float_left_inline_size;
LayoutUnit float_right_inline_size; LayoutUnit float_right_inline_size;
// Extrinsic block-size of the containing block.
LayoutUnit extrinsic_block_size = NGSizeIndefinite;
// Whether to return the size as a content-box size or border-box size. // Whether to return the size as a content-box size or border-box size.
NGMinMaxSizeType size_type = NGMinMaxSizeType::kBorderBoxSize; NGMinMaxSizeType size_type = NGMinMaxSizeType::kBorderBoxSize;
}; };
......
...@@ -426,11 +426,12 @@ MinMaxSize ComputeMinAndMaxContentContribution( ...@@ -426,11 +426,12 @@ MinMaxSize ComputeMinAndMaxContentContribution(
} }
MinMaxSize ComputeMinAndMaxContentContribution( MinMaxSize ComputeMinAndMaxContentContribution(
WritingMode writing_mode, const ComputedStyle& parent_style,
NGLayoutInputNode node, NGLayoutInputNode child,
const MinMaxSizeInput& input, const MinMaxSizeInput& input) {
const NGConstraintSpace* constraint_space) { const ComputedStyle& child_style = child.Style();
LayoutBox* box = node.GetLayoutBox(); WritingMode parent_writing_mode = parent_style.GetWritingMode();
LayoutBox* box = child.GetLayoutBox();
if (box->NeedsPreferredWidthsRecalculation()) { if (box->NeedsPreferredWidthsRecalculation()) {
// Some objects (when there's an intrinsic ratio) have their min/max inline // Some objects (when there's an intrinsic ratio) have their min/max inline
...@@ -441,7 +442,8 @@ MinMaxSize ComputeMinAndMaxContentContribution( ...@@ -441,7 +442,8 @@ MinMaxSize ComputeMinAndMaxContentContribution(
box->SetPreferredLogicalWidthsDirty(); box->SetPreferredLogicalWidthsDirty();
} }
if (IsParallelWritingMode(writing_mode, node.Style().GetWritingMode())) { if (IsParallelWritingMode(parent_writing_mode,
child_style.GetWritingMode())) {
if (!box->PreferredLogicalWidthsDirty()) { if (!box->PreferredLogicalWidthsDirty()) {
return {box->MinPreferredLogicalWidth(), box->MaxPreferredLogicalWidth()}; return {box->MinPreferredLogicalWidth(), box->MaxPreferredLogicalWidth()};
} }
...@@ -455,38 +457,24 @@ MinMaxSize ComputeMinAndMaxContentContribution( ...@@ -455,38 +457,24 @@ MinMaxSize ComputeMinAndMaxContentContribution(
} }
base::Optional<MinMaxSize> minmax; base::Optional<MinMaxSize> minmax;
if (NeedMinMaxSizeForContentContribution(writing_mode, node.Style())) { if (NeedMinMaxSizeForContentContribution(parent_writing_mode, child_style)) {
NGConstraintSpace adjusted_constraint_space; // We need to set up a constraint space with correct fallback available
if (constraint_space) { // inline size in case of orthogonal children.
// TODO(layout-ng): Check if our constraint space produces spec-compliant NGConstraintSpace indefinite_constraint_space;
// outputs. const NGConstraintSpace* child_constraint_space = nullptr;
// It is important to set a floats bfc block offset so that we don't get a if (!IsParallelWritingMode(parent_writing_mode,
// partial layout. It is also important that we shrink to fit, by child_style.GetWritingMode())) {
// definition. indefinite_constraint_space =
adjusted_constraint_space = CreateIndefiniteConstraintSpaceForChild(parent_style, child);
NGConstraintSpaceBuilder( child_constraint_space = &indefinite_constraint_space;
*constraint_space, node.Style().GetWritingMode(),
/* is_new_fc */ constraint_space->IsNewFormattingContext())
.SetOrthogonalFallbackInlineSize(
// TODO(mstensho): This is broken and needs to be cleaned
// up. First of all, we don't know whom |constraint_space| is
// for. Could be for |node|, or could be for its parent,
// depending on call site.
constraint_space->AvailableSize().inline_size)
.SetAvailableSize(constraint_space->AvailableSize())
.SetPercentageResolutionSize(
constraint_space->PercentageResolutionSize())
.SetFloatsBfcBlockOffset(LayoutUnit())
.SetIsShrinkToFit(true)
.ToConstraintSpace();
constraint_space = &adjusted_constraint_space;
} }
minmax = node.ComputeMinMaxSize(writing_mode, input, constraint_space); minmax = child.ComputeMinMaxSize(parent_writing_mode, input,
child_constraint_space);
} }
MinMaxSize sizes = MinMaxSize sizes = ComputeMinAndMaxContentContribution(parent_writing_mode,
ComputeMinAndMaxContentContribution(writing_mode, node.Style(), minmax); child_style, minmax);
if (IsParallelWritingMode(writing_mode, node.Style().GetWritingMode())) if (IsParallelWritingMode(parent_writing_mode, child_style.GetWritingMode()))
box->SetPreferredLogicalWidthsFromNG(sizes); box->SetPreferredLogicalWidthsFromNG(sizes);
return sizes; return sizes;
} }
...@@ -1155,10 +1143,17 @@ LayoutUnit CalculateOrthogonalFallbackInlineSize( ...@@ -1155,10 +1143,17 @@ LayoutUnit CalculateOrthogonalFallbackInlineSize(
else else
fallback_size = orthogonal_children_containing_block_size.width; fallback_size = orthogonal_children_containing_block_size.width;
if (!parent_style.LogicalMaxHeight().IsFixed()) LayoutUnit size(LayoutUnit::Max());
return fallback_size; if (parent_style.LogicalHeight().IsFixed()) {
// Note that during layout, fixed size will already be taken care of (and
LayoutUnit size(parent_style.LogicalMaxHeight().GetFloatValue()); // set in the constraint space), but when calculating intrinsic sizes of
// orthogonal children, that won't be the case.
size = LayoutUnit(parent_style.LogicalHeight().GetFloatValue());
}
if (parent_style.LogicalMaxHeight().IsFixed()) {
size = std::min(
size, LayoutUnit(parent_style.LogicalMaxHeight().GetFloatValue()));
}
if (parent_style.LogicalMinHeight().IsFixed()) { if (parent_style.LogicalMinHeight().IsFixed()) {
size = std::max( size = std::max(
size, LayoutUnit(parent_style.LogicalMinHeight().GetFloatValue())); size, LayoutUnit(parent_style.LogicalMinHeight().GetFloatValue()));
......
...@@ -118,19 +118,17 @@ ComputeMinAndMaxContentContribution(WritingMode writing_mode, ...@@ -118,19 +118,17 @@ ComputeMinAndMaxContentContribution(WritingMode writing_mode,
const base::Optional<MinMaxSize>&); const base::Optional<MinMaxSize>&);
// A version of ComputeMinAndMaxContentContribution that does not require you // A version of ComputeMinAndMaxContentContribution that does not require you
// to compute the min/max content size of the node. Instead, this function // to compute the min/max content size of the child. Instead, this function
// will compute it if necessary. // will compute it if necessary.
// writing_mode is the desired output writing mode (ie. often the writing mode // |child| is the node of which to compute the min/max content contribution.
// of the parent); node is the node of which to compute the min/max content // Note that if the writing mode of the child is orthogonal to that of the
// contribution. // parent, we'll still return the inline min/max contribution in the writing
// If a constraint space is provided, this function will convert it to the // mode of the parent (i.e. typically something based on the preferred *block*
// correct writing mode and otherwise make sure it is suitable for computing // size of the child).
// the desired value.
MinMaxSize ComputeMinAndMaxContentContribution( MinMaxSize ComputeMinAndMaxContentContribution(
WritingMode writing_mode, const ComputedStyle& parent_style,
NGLayoutInputNode node, NGLayoutInputNode child,
const MinMaxSizeInput& input, const MinMaxSizeInput& input);
const NGConstraintSpace* space = nullptr);
// Resolves the computed value in style.logicalWidth (Length) to a layout unit, // Resolves the computed value in style.logicalWidth (Length) to a layout unit,
// then constrains the result by the resolved min logical width and max logical // then constrains the result by the resolved min logical width and max logical
......
...@@ -23,22 +23,25 @@ bool AdjustToClearance(LayoutUnit clearance_offset, NGBfcOffset* offset) { ...@@ -23,22 +23,25 @@ bool AdjustToClearance(LayoutUnit clearance_offset, NGBfcOffset* offset) {
return false; return false;
} }
NGConstraintSpace CreateExtrinsicConstraintSpaceForChild( NGConstraintSpace CreateIndefiniteConstraintSpaceForChild(
const NGConstraintSpace& container_constraint_space,
const ComputedStyle& container_style, const ComputedStyle& container_style,
LayoutUnit container_extrinsic_block_size,
NGLayoutInputNode child) { NGLayoutInputNode child) {
NGLogicalSize extrinsic_size(NGSizeIndefinite, NGLogicalSize indefinite_size(NGSizeIndefinite, NGSizeIndefinite);
container_extrinsic_block_size); LayoutUnit fallback_inline_size = NGSizeIndefinite;
LayoutUnit fallback_inline_size = CalculateOrthogonalFallbackInlineSize( WritingMode parent_writing_mode = container_style.GetWritingMode();
container_style, container_constraint_space.InitialContainingBlockSize()); WritingMode child_writing_mode = child.Style().GetWritingMode();
if (!IsParallelWritingMode(parent_writing_mode, child_writing_mode)) {
fallback_inline_size = CalculateOrthogonalFallbackInlineSize(
container_style, child.InitialContainingBlockSize());
}
return NGConstraintSpaceBuilder(container_constraint_space, return NGConstraintSpaceBuilder(parent_writing_mode, child_writing_mode,
child.Style().GetWritingMode(), child.InitialContainingBlockSize(),
child.CreatesNewFormattingContext()) child.CreatesNewFormattingContext())
.SetOrthogonalFallbackInlineSize(fallback_inline_size) .SetOrthogonalFallbackInlineSize(fallback_inline_size)
.SetAvailableSize(extrinsic_size) .SetAvailableSize(indefinite_size)
.SetPercentageResolutionSize(extrinsic_size) .SetPercentageResolutionSize(indefinite_size)
.SetReplacedPercentageResolutionSize(indefinite_size)
.SetIsIntermediateLayout(true) .SetIsIntermediateLayout(true)
.SetFloatsBfcBlockOffset(LayoutUnit()) .SetFloatsBfcBlockOffset(LayoutUnit())
.ToConstraintSpace(); .ToConstraintSpace();
......
...@@ -20,24 +20,13 @@ struct NGBfcOffset; ...@@ -20,24 +20,13 @@ struct NGBfcOffset;
CORE_EXPORT bool AdjustToClearance(LayoutUnit clearance_offset, CORE_EXPORT bool AdjustToClearance(LayoutUnit clearance_offset,
NGBfcOffset* offset); NGBfcOffset* offset);
// Create a child constraint space with only extrinsic block sizing data. This // Create a child constraint space with no sizing data, except for fallback
// will and can not be used for final layout, but is needed in an intermediate // inline sizing for orthongonal flow roots. This will not and can not be used
// measure pass that calculates the min/max size contribution from a child that // for final layout, but is needed in an intermediate measure pass that
// establishes an orthogonal flow root. // calculates the min/max size contribution from a child that establishes an
// // orthogonal flow root.
// Note that it's the child's *block* size that will be propagated as min/max NGConstraintSpace CreateIndefiniteConstraintSpaceForChild(
// inline size to the container. Therefore it's crucial to provide the child
// with an available inline size (which can be derived from the block size of
// the container if definite). We'll provide any extrinsic available block size
// that we have. This includes fixed and resolvable percentage sizes, for
// instance, while auto will not resolve. If no extrinsic size can be
// determined, we will resort to using a fallback later on, such as the initial
// containing block size. Spec:
// https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto
NGConstraintSpace CreateExtrinsicConstraintSpaceForChild(
const NGConstraintSpace& container_constraint_space,
const ComputedStyle& container_style, const ComputedStyle& container_style,
LayoutUnit container_extrinsic_block_size,
NGLayoutInputNode child); NGLayoutInputNode child);
} // namespace blink } // namespace blink
......
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