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(
const ComputedStyle& float_style = float_node.Style();
MinMaxSizeInput zero_input; // Floats don't intrude into floats.
// We'll need extrinsic sizing data when computing min/max for orthogonal
// flow roots.
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);
MinMaxSize child_sizes =
ComputeMinAndMaxContentContribution(style, float_node, zero_input);
LayoutUnit child_inline_margins =
ComputeMinMaxMargins(style, float_node).InlineSum();
......
......@@ -806,11 +806,10 @@ void NGLineBreaker::HandleAtomicInline(const NGInlineItem& item) {
*item_result->layout_result->PhysicalFragment())
.InlineSize();
} else {
NGBlockNode block_node(ToLayoutBox(item.GetLayoutObject()));
NGBlockNode child(ToLayoutBox(item.GetLayoutObject()));
MinMaxSizeInput input;
MinMaxSize sizes = ComputeMinAndMaxContentContribution(
constraint_space_.GetWritingMode(), block_node, input,
&constraint_space_);
MinMaxSize sizes =
ComputeMinAndMaxContentContribution(node_.Style(), child, input);
item_result->inline_size = mode_ == NGLineBreakerMode::kMinContent
? sizes.min_size
: sizes.max_size;
......
......@@ -200,14 +200,6 @@ base::Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize(
LayoutUnit float_left_inline_size = input.float_left_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;
child = child.NextSibling()) {
if (child.IsOutOfFlowPositioned() || child.IsColumnSpanAll())
......@@ -238,10 +230,8 @@ base::Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize(
}
MinMaxSizeInput child_input;
if (child.IsInline() || child.IsAnonymousBlock()) {
child_input = {float_left_inline_size, float_right_inline_size,
extrinsic_block_size};
}
if (child.IsInline() || child.IsAnonymousBlock())
child_input = {float_left_inline_size, float_right_inline_size};
MinMaxSize child_sizes;
if (child.IsInline()) {
......@@ -250,27 +240,12 @@ base::Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize(
// all inline nodes following |child| and their descendants, and produces
// an anonymous box that contains all line boxes.
// |NextSibling| returns the next block sibling, or nullptr, skipping all
// following inline siblings and descendants. We'll pass our constraint
// space here, so that floated orthogonal flow roots can calculate an
// extrinsic constraint space.
child_sizes = child.ComputeMinMaxSize(Style().GetWritingMode(),
child_input, &constraint_space_);
// following inline siblings and descendants.
child_sizes =
child.ComputeMinMaxSize(Style().GetWritingMode(), child_input);
} else {
// We'll need extrinsic sizing data when computing min/max for orthogonal
// flow roots. If the child is a block node, we can check that right away,
// 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);
child_sizes =
ComputeMinAndMaxContentContribution(Style(), child, child_input);
}
DCHECK_LE(child_sizes.min_size, child_sizes.max_size) << child.ToString();
......
......@@ -148,33 +148,7 @@ base::Optional<MinMaxSize> NGFieldsetLayoutAlgorithm::ComputeMinMaxSize(
return sizes;
if (NGBlockNode legend = Node().GetRenderedLegend()) {
// We'll need extrinsic sizing data when computing min/max for orthogonal
// 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 = ComputeMinAndMaxContentContribution(Style(), legend, input);
sizes += ComputeMinMaxMargins(Style(), legend).InlineSum();
}
// The fieldset content includes the fieldset padding (and any scrollbars),
......@@ -183,8 +157,8 @@ base::Optional<MinMaxSize> NGFieldsetLayoutAlgorithm::ComputeMinMaxSize(
sizes += ComputePadding(ConstraintSpace(), node_.Style()).InlineSum();
if (NGBlockNode content = Node().GetFieldsetContent()) {
MinMaxSize content_minmax = ComputeMinAndMaxContentContribution(
Style().GetWritingMode(), content, input);
MinMaxSize content_minmax =
ComputeMinAndMaxContentContribution(Style(), content, input);
content_minmax += ComputeMinMaxMargins(Style(), content).InlineSum();
sizes.Encompass(content_minmax);
}
......
......@@ -32,15 +32,11 @@ enum class NGMinMaxSizeType { kContentBoxSize, kBorderBoxSize };
// 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
// them. Additionally, orthogonal writing mode roots will need the extrinsic
// block-size of the container.
// them.
struct MinMaxSizeInput {
LayoutUnit float_left_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.
NGMinMaxSizeType size_type = NGMinMaxSizeType::kBorderBoxSize;
};
......
......@@ -426,11 +426,12 @@ MinMaxSize ComputeMinAndMaxContentContribution(
}
MinMaxSize ComputeMinAndMaxContentContribution(
WritingMode writing_mode,
NGLayoutInputNode node,
const MinMaxSizeInput& input,
const NGConstraintSpace* constraint_space) {
LayoutBox* box = node.GetLayoutBox();
const ComputedStyle& parent_style,
NGLayoutInputNode child,
const MinMaxSizeInput& input) {
const ComputedStyle& child_style = child.Style();
WritingMode parent_writing_mode = parent_style.GetWritingMode();
LayoutBox* box = child.GetLayoutBox();
if (box->NeedsPreferredWidthsRecalculation()) {
// Some objects (when there's an intrinsic ratio) have their min/max inline
......@@ -441,7 +442,8 @@ MinMaxSize ComputeMinAndMaxContentContribution(
box->SetPreferredLogicalWidthsDirty();
}
if (IsParallelWritingMode(writing_mode, node.Style().GetWritingMode())) {
if (IsParallelWritingMode(parent_writing_mode,
child_style.GetWritingMode())) {
if (!box->PreferredLogicalWidthsDirty()) {
return {box->MinPreferredLogicalWidth(), box->MaxPreferredLogicalWidth()};
}
......@@ -455,38 +457,24 @@ MinMaxSize ComputeMinAndMaxContentContribution(
}
base::Optional<MinMaxSize> minmax;
if (NeedMinMaxSizeForContentContribution(writing_mode, node.Style())) {
NGConstraintSpace adjusted_constraint_space;
if (constraint_space) {
// TODO(layout-ng): Check if our constraint space produces spec-compliant
// outputs.
// It is important to set a floats bfc block offset so that we don't get a
// partial layout. It is also important that we shrink to fit, by
// definition.
adjusted_constraint_space =
NGConstraintSpaceBuilder(
*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;
if (NeedMinMaxSizeForContentContribution(parent_writing_mode, child_style)) {
// We need to set up a constraint space with correct fallback available
// inline size in case of orthogonal children.
NGConstraintSpace indefinite_constraint_space;
const NGConstraintSpace* child_constraint_space = nullptr;
if (!IsParallelWritingMode(parent_writing_mode,
child_style.GetWritingMode())) {
indefinite_constraint_space =
CreateIndefiniteConstraintSpaceForChild(parent_style, child);
child_constraint_space = &indefinite_constraint_space;
}
minmax = node.ComputeMinMaxSize(writing_mode, input, constraint_space);
minmax = child.ComputeMinMaxSize(parent_writing_mode, input,
child_constraint_space);
}
MinMaxSize sizes =
ComputeMinAndMaxContentContribution(writing_mode, node.Style(), minmax);
if (IsParallelWritingMode(writing_mode, node.Style().GetWritingMode()))
MinMaxSize sizes = ComputeMinAndMaxContentContribution(parent_writing_mode,
child_style, minmax);
if (IsParallelWritingMode(parent_writing_mode, child_style.GetWritingMode()))
box->SetPreferredLogicalWidthsFromNG(sizes);
return sizes;
}
......@@ -1155,10 +1143,17 @@ LayoutUnit CalculateOrthogonalFallbackInlineSize(
else
fallback_size = orthogonal_children_containing_block_size.width;
if (!parent_style.LogicalMaxHeight().IsFixed())
return fallback_size;
LayoutUnit size(parent_style.LogicalMaxHeight().GetFloatValue());
LayoutUnit size(LayoutUnit::Max());
if (parent_style.LogicalHeight().IsFixed()) {
// Note that during layout, fixed size will already be taken care of (and
// 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()) {
size = std::max(
size, LayoutUnit(parent_style.LogicalMinHeight().GetFloatValue()));
......
......@@ -118,19 +118,17 @@ ComputeMinAndMaxContentContribution(WritingMode writing_mode,
const base::Optional<MinMaxSize>&);
// 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.
// writing_mode is the desired output writing mode (ie. often the writing mode
// of the parent); node is the node of which to compute the min/max content
// contribution.
// If a constraint space is provided, this function will convert it to the
// correct writing mode and otherwise make sure it is suitable for computing
// the desired value.
// |child| is the node of which to compute the min/max content contribution.
// Note that if the writing mode of the child is orthogonal to that of the
// parent, we'll still return the inline min/max contribution in the writing
// mode of the parent (i.e. typically something based on the preferred *block*
// size of the child).
MinMaxSize ComputeMinAndMaxContentContribution(
WritingMode writing_mode,
NGLayoutInputNode node,
const MinMaxSizeInput& input,
const NGConstraintSpace* space = nullptr);
const ComputedStyle& parent_style,
NGLayoutInputNode child,
const MinMaxSizeInput& input);
// 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
......
......@@ -23,22 +23,25 @@ bool AdjustToClearance(LayoutUnit clearance_offset, NGBfcOffset* offset) {
return false;
}
NGConstraintSpace CreateExtrinsicConstraintSpaceForChild(
const NGConstraintSpace& container_constraint_space,
NGConstraintSpace CreateIndefiniteConstraintSpaceForChild(
const ComputedStyle& container_style,
LayoutUnit container_extrinsic_block_size,
NGLayoutInputNode child) {
NGLogicalSize extrinsic_size(NGSizeIndefinite,
container_extrinsic_block_size);
LayoutUnit fallback_inline_size = CalculateOrthogonalFallbackInlineSize(
container_style, container_constraint_space.InitialContainingBlockSize());
NGLogicalSize indefinite_size(NGSizeIndefinite, NGSizeIndefinite);
LayoutUnit fallback_inline_size = NGSizeIndefinite;
WritingMode parent_writing_mode = container_style.GetWritingMode();
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,
child.Style().GetWritingMode(),
return NGConstraintSpaceBuilder(parent_writing_mode, child_writing_mode,
child.InitialContainingBlockSize(),
child.CreatesNewFormattingContext())
.SetOrthogonalFallbackInlineSize(fallback_inline_size)
.SetAvailableSize(extrinsic_size)
.SetPercentageResolutionSize(extrinsic_size)
.SetAvailableSize(indefinite_size)
.SetPercentageResolutionSize(indefinite_size)
.SetReplacedPercentageResolutionSize(indefinite_size)
.SetIsIntermediateLayout(true)
.SetFloatsBfcBlockOffset(LayoutUnit())
.ToConstraintSpace();
......
......@@ -20,24 +20,13 @@ struct NGBfcOffset;
CORE_EXPORT bool AdjustToClearance(LayoutUnit clearance_offset,
NGBfcOffset* offset);
// Create a child constraint space with only extrinsic block sizing data. This
// will and can not be used for final layout, but is needed in an intermediate
// measure pass that 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
// 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,
// Create a child constraint space with no sizing data, except for fallback
// inline sizing for orthongonal flow roots. This will not and can not be used
// for final layout, but is needed in an intermediate measure pass that
// calculates the min/max size contribution from a child that establishes an
// orthogonal flow root.
NGConstraintSpace CreateIndefiniteConstraintSpaceForChild(
const ComputedStyle& container_style,
LayoutUnit container_extrinsic_block_size,
NGLayoutInputNode child);
} // 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