| Index: third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
|
| diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
|
| index 64b252dd5455c6a3143da6fb3a8b188741a36344..5e6ff3e14e7fc0f1f438c46db09ef0bf0656c5ab 100644
|
| --- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
|
| +++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
|
| @@ -66,6 +66,8 @@ bool IsEmptyFragment(NGWritingMode writing_mode,
|
| if (!layout_result.PhysicalFragment())
|
| return true;
|
|
|
| + // TODO(ikilpatrick): This is kinda wrong, we need a bit on the
|
| + // NGLayoutResult to properly determine if something is empty.
|
| NGFragment fragment(writing_mode, layout_result.PhysicalFragment().Get());
|
| if (!fragment.BlockSize())
|
| return true;
|
| @@ -105,6 +107,8 @@ void PositionPendingFloats(
|
| const auto positioned_floats = PositionFloats(
|
| origin_block_offset, from_block_offset, *unpositioned_floats, space);
|
|
|
| + // TODO(ikilpatrick): Add DCHECK that any positioned floats are children.
|
| +
|
| for (const auto& positioned_float : positioned_floats)
|
| container_builder->AddPositionedFloat(positioned_float);
|
|
|
| @@ -267,42 +271,14 @@ RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
|
| HandleOutOfFlowPositioned(previous_inflow_position.value(),
|
| ToNGBlockNode(child));
|
| } else if (child.IsFloating()) {
|
| - HandleFloating(previous_inflow_position.value(), ToNGBlockNode(child),
|
| - ToNGBlockBreakToken(child_break_token));
|
| + HandleFloat(previous_inflow_position.value(), ToNGBlockNode(child),
|
| + ToNGBlockBreakToken(child_break_token));
|
| } else {
|
| - // TODO(ikilpatrick): Refactor this else branch.
|
| - WTF::Optional<NGInflowChildData> child_data =
|
| - PrepareChildLayout(previous_inflow_position.value(), child);
|
| -
|
| - // If PrepareChildLayout resolved our BFC offset, abort the layout.
|
| - if (!child_data) {
|
| - DCHECK(container_builder_.BfcOffset());
|
| - container_builder_.SwapUnpositionedFloats(&unpositioned_floats_);
|
| - return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved);
|
| - }
|
| -
|
| - RefPtr<NGConstraintSpace> child_space =
|
| - CreateConstraintSpaceForChild(child, child_data.value());
|
| - RefPtr<NGLayoutResult> layout_result =
|
| - child.Layout(child_space.Get(), child_break_token);
|
| -
|
| - // A child may have aborted its layout if it resolved its BFC offset. If
|
| - // we don't have a BFC offset yet, we need to propagate the abortion up
|
| - // to our parent.
|
| - if (layout_result->Status() == NGLayoutResult::kBfcOffsetResolved &&
|
| - !container_builder_.BfcOffset()) {
|
| - MaybeUpdateFragmentBfcOffset(
|
| - ConstraintSpace(), layout_result->BfcOffset().value().block_offset,
|
| - &container_builder_);
|
| - container_builder_.SwapUnpositionedFloats(&unpositioned_floats_);
|
| - return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved);
|
| - }
|
| + previous_inflow_position = HandleInflow(previous_inflow_position.value(),
|
| + child, child_break_token);
|
|
|
| - previous_inflow_position = FinishChildLayout(
|
| - *child_space, previous_inflow_position.value(), child_data.value(),
|
| - child, child_break_token, std::move(layout_result));
|
| -
|
| - // If FinishChildLayout resolved our BFC offset, abort the layout.
|
| + // If we didn't receive a NGPreviousInflowPosition from HandleInflow, we
|
| + // need to abort the layout as our BFC offset was resolved.
|
| if (!previous_inflow_position) {
|
| container_builder_.SwapUnpositionedFloats(&unpositioned_floats_);
|
| return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved);
|
| @@ -420,7 +396,7 @@ void NGBlockLayoutAlgorithm::HandleOutOfFlowPositioned(
|
| container_builder_.AddOutOfFlowChildCandidate(child, offset);
|
| }
|
|
|
| -void NGBlockLayoutAlgorithm::HandleFloating(
|
| +void NGBlockLayoutAlgorithm::HandleFloat(
|
| const NGPreviousInflowPosition& previous_inflow_position,
|
| NGBlockNode child,
|
| NGBlockBreakToken* token) {
|
| @@ -455,17 +431,13 @@ void NGBlockLayoutAlgorithm::HandleFloating(
|
| }
|
| }
|
|
|
| -WTF::Optional<NGInflowChildData> NGBlockLayoutAlgorithm::PrepareChildLayout(
|
| +WTF::Optional<NGPreviousInflowPosition> NGBlockLayoutAlgorithm::HandleInflow(
|
| const NGPreviousInflowPosition& previous_inflow_position,
|
| - NGLayoutInputNode child) {
|
| + NGLayoutInputNode child,
|
| + NGBreakToken* child_break_token) {
|
| DCHECK(child);
|
| DCHECK(!child.IsFloating());
|
| -
|
| - LayoutUnit bfc_block_offset = previous_inflow_position.bfc_block_offset;
|
| -
|
| - // Calculate margins in parent's writing mode.
|
| - NGBoxStrut margins = CalculateMargins(child);
|
| - NGMarginStrut margin_strut = previous_inflow_position.margin_strut;
|
| + DCHECK(!child.IsOutOfFlowPositioned());
|
|
|
| bool should_position_pending_floats =
|
| !child.CreatesNewFormattingContext() &&
|
| @@ -473,10 +445,11 @@ WTF::Optional<NGInflowChildData> NGBlockLayoutAlgorithm::PrepareChildLayout(
|
| child.Style());
|
|
|
| // Children which may clear a float need to force all the pending floats to
|
| - // be positioned before layout. This also resolves the fragment's bfc offset.
|
| + // be positioned before layout. This also resolves our BFC offset.
|
| if (should_position_pending_floats) {
|
| LayoutUnit origin_point_block_offset =
|
| - bfc_block_offset + margin_strut.Sum();
|
| + previous_inflow_position.bfc_block_offset +
|
| + previous_inflow_position.margin_strut.Sum();
|
| bool updated = MaybeUpdateFragmentBfcOffset(
|
| ConstraintSpace(), origin_point_block_offset, &container_builder_);
|
|
|
| @@ -489,29 +462,13 @@ WTF::Optional<NGInflowChildData> NGBlockLayoutAlgorithm::PrepareChildLayout(
|
| &unpositioned_floats_, MutableConstraintSpace());
|
| }
|
|
|
| - NGLogicalOffset child_bfc_offset = {
|
| - ConstraintSpace().BfcOffset().inline_offset +
|
| - border_scrollbar_padding_.inline_start + margins.inline_start,
|
| - bfc_block_offset};
|
| -
|
| - // Append the current margin strut with child's block start margin.
|
| - // Non empty border/padding, and new FC use cases are handled inside of the
|
| - // child's layout
|
| - margin_strut.Append(margins.block_start);
|
| -
|
| - return NGInflowChildData{child_bfc_offset, margin_strut, margins};
|
| -}
|
| -
|
| -WTF::Optional<NGPreviousInflowPosition>
|
| -NGBlockLayoutAlgorithm::FinishChildLayout(
|
| - const NGConstraintSpace& child_space,
|
| - const NGPreviousInflowPosition& previous_inflow_position,
|
| - const NGInflowChildData& child_data,
|
| - NGLayoutInputNode child,
|
| - NGBreakToken* child_break_token,
|
| - RefPtr<NGLayoutResult> layout_result) {
|
| - // TODO(ikilpatrick): Split this function into two - one for positioning, and
|
| - // the other for producing NGPreviousInflowPosition.
|
| + // Perform layout on the child.
|
| + NGInflowChildData child_data =
|
| + ComputeChildData(previous_inflow_position, child);
|
| + RefPtr<NGConstraintSpace> child_space =
|
| + CreateConstraintSpaceForChild(child, child_data);
|
| + RefPtr<NGLayoutResult> layout_result =
|
| + child.Layout(child_space.Get(), child_break_token);
|
|
|
| // If we don't know our BFC offset yet, we need to copy the list of
|
| // unpositioned floats from the child's layout result.
|
| @@ -524,19 +481,38 @@ NGBlockLayoutAlgorithm::FinishChildLayout(
|
| //
|
| // TODO(ikilpatrick): a more optimal version of this is to set
|
| // abort_when_bfc_resolved_, if the child tree _added_ any floats.
|
| - if (!container_builder_.BfcOffset() &&
|
| - !child_space.IsNewFormattingContext()) {
|
| + if (!container_builder_.BfcOffset() && !child.CreatesNewFormattingContext()) {
|
| unpositioned_floats_ = layout_result->UnpositionedFloats();
|
| abort_when_bfc_resolved_ |= !layout_result->UnpositionedFloats().IsEmpty();
|
| - if (child_space.FloatsBfcOffset())
|
| + if (child_space->FloatsBfcOffset())
|
| DCHECK(layout_result->UnpositionedFloats().IsEmpty());
|
| }
|
|
|
| - // Determine the fragment's position in the parent space.
|
| + // A child may have aborted its layout if it resolved its BFC offset. If
|
| + // we don't have a BFC offset yet, we need to propagate the abortion up
|
| + // to our parent.
|
| + if (layout_result->Status() == NGLayoutResult::kBfcOffsetResolved &&
|
| + !container_builder_.BfcOffset()) {
|
| + DCHECK(!child.CreatesNewFormattingContext());
|
| +
|
| + MaybeUpdateFragmentBfcOffset(
|
| + ConstraintSpace(), layout_result->BfcOffset().value().block_offset,
|
| + &container_builder_);
|
| +
|
| + // NOTE: Unlike other aborts, we don't try check if we *should* abort with
|
| + // abort_when_bfc_resolved_, this is simply propagating an abort up to a
|
| + // node which is able to restart the layout (a node that has resolved its
|
| + // BFC offset).
|
| + return WTF::nullopt;
|
| + }
|
| +
|
| + // We try and position the child within the block formatting context. This
|
| + // may cause our BFC offset to be resolved, in which case we should abort our
|
| + // layout if needed.
|
| WTF::Optional<NGLogicalOffset> child_bfc_offset;
|
| if (child.CreatesNewFormattingContext()) {
|
| if (!PositionNewFc(child, previous_inflow_position, *layout_result,
|
| - child_data, child_space, &child_bfc_offset))
|
| + child_data, *child_space, &child_bfc_offset))
|
| return WTF::nullopt;
|
| } else if (layout_result->BfcOffset()) {
|
| if (!PositionWithBfcOffset(layout_result->BfcOffset().value(),
|
| @@ -544,18 +520,26 @@ NGBlockLayoutAlgorithm::FinishChildLayout(
|
| return WTF::nullopt;
|
| } else if (container_builder_.BfcOffset()) {
|
| child_bfc_offset =
|
| - PositionWithParentBfc(child_space, child_data, *layout_result);
|
| + PositionWithParentBfc(*child_space, child_data, *layout_result);
|
| } else
|
| DCHECK(IsEmptyFragment(ConstraintSpace().WritingMode(), *layout_result));
|
|
|
| + // We need to layout a child if we know its BFC offset and:
|
| + // - It aborted its layout as it resolved its BFC offset.
|
| + // - It has some unpositioned floats.
|
| if ((layout_result->Status() == NGLayoutResult::kBfcOffsetResolved ||
|
| !layout_result->UnpositionedFloats().IsEmpty()) &&
|
| child_bfc_offset) {
|
| RefPtr<NGConstraintSpace> new_child_space =
|
| CreateConstraintSpaceForChild(child, child_data, child_bfc_offset);
|
| layout_result = child.Layout(new_child_space.Get(), child_break_token);
|
| +
|
| + DCHECK_EQ(layout_result->Status(), NGLayoutResult::kSuccess);
|
| }
|
|
|
| + // We must have an actual fragment at this stage.
|
| + DCHECK(layout_result->PhysicalFragment().Get());
|
| +
|
| NGBoxFragment fragment(
|
| ConstraintSpace().WritingMode(),
|
| ToNGPhysicalBoxFragment(layout_result->PhysicalFragment().Get()));
|
| @@ -563,12 +547,6 @@ NGBlockLayoutAlgorithm::FinishChildLayout(
|
| NGLogicalOffset logical_offset =
|
| CalculateLogicalOffset(child_data.margins, child_bfc_offset);
|
|
|
| - NGMarginStrut margin_strut = layout_result->EndMarginStrut();
|
| - margin_strut.Append(child_data.margins.block_end);
|
| -
|
| - // TODO(ikilpatrick): Refactor below such that we don't have to rely on the
|
| - // if (fragment) ... checks.
|
| -
|
| // Only modify content_size_ if the fragment's BlockSize is not empty. This is
|
| // needed to prevent the situation when logical_offset is included in
|
| // content_size_ for empty blocks. Example:
|
| @@ -576,20 +554,51 @@ NGBlockLayoutAlgorithm::FinishChildLayout(
|
| // <div style="margin-top: 8px"></div>
|
| // <div style="margin-top: 10px"></div>
|
| // </div>
|
| - if (fragment) {
|
| - if (fragment.BlockSize()) {
|
| - content_size_ = std::max(
|
| - content_size_, logical_offset.block_offset + fragment.BlockSize());
|
| - }
|
| - max_inline_size_ =
|
| - std::max(max_inline_size_, fragment.InlineSize() +
|
| - child_data.margins.InlineSum() +
|
| - border_scrollbar_padding_.InlineSum());
|
| + if (fragment.BlockSize()) {
|
| + content_size_ = std::max(
|
| + content_size_, logical_offset.block_offset + fragment.BlockSize());
|
| }
|
| + max_inline_size_ = std::max(
|
| + max_inline_size_, fragment.InlineSize() + child_data.margins.InlineSum() +
|
| + border_scrollbar_padding_.InlineSum());
|
| +
|
| + container_builder_.AddChild(layout_result, logical_offset);
|
|
|
| - if (fragment)
|
| - container_builder_.AddChild(layout_result, logical_offset);
|
| + return ComputeInflowPosition(previous_inflow_position, child_data,
|
| + child_bfc_offset, logical_offset, *layout_result,
|
| + fragment);
|
| +}
|
|
|
| +NGInflowChildData NGBlockLayoutAlgorithm::ComputeChildData(
|
| + const NGPreviousInflowPosition& previous_inflow_position,
|
| + NGLayoutInputNode child) {
|
| + DCHECK(child);
|
| + DCHECK(!child.IsFloating());
|
| +
|
| + // Calculate margins in parent's writing mode.
|
| + NGBoxStrut margins = CalculateMargins(child);
|
| +
|
| + // Append the current margin strut with child's block start margin.
|
| + // Non empty border/padding, and new FC use cases are handled inside of the
|
| + // child's layout
|
| + NGMarginStrut margin_strut = previous_inflow_position.margin_strut;
|
| + margin_strut.Append(margins.block_start);
|
| +
|
| + NGLogicalOffset child_bfc_offset = {
|
| + ConstraintSpace().BfcOffset().inline_offset +
|
| + border_scrollbar_padding_.inline_start + margins.inline_start,
|
| + previous_inflow_position.bfc_block_offset};
|
| +
|
| + return {child_bfc_offset, margin_strut, margins};
|
| +}
|
| +
|
| +NGPreviousInflowPosition NGBlockLayoutAlgorithm::ComputeInflowPosition(
|
| + const NGPreviousInflowPosition& previous_inflow_position,
|
| + const NGInflowChildData& child_data,
|
| + const WTF::Optional<NGLogicalOffset>& child_bfc_offset,
|
| + const NGLogicalOffset& logical_offset,
|
| + const NGLayoutResult& layout_result,
|
| + const NGFragment& fragment) {
|
| // Determine the child's end BFC block offset and logical offset, for the
|
| // next child to use.
|
| LayoutUnit child_end_bfc_block_offset;
|
| @@ -598,12 +607,12 @@ NGBlockLayoutAlgorithm::FinishChildLayout(
|
| if (child_bfc_offset) {
|
| // TODO(crbug.com/716930): I think the layout_result->BfcOffset() condition
|
| // here can be removed once we've removed inline splitting.
|
| - if (fragment && (fragment.BlockSize() || layout_result->BfcOffset())) {
|
| + if (fragment.BlockSize() || layout_result.BfcOffset()) {
|
| child_end_bfc_block_offset =
|
| child_bfc_offset.value().block_offset + fragment.BlockSize();
|
| logical_block_offset = logical_offset.block_offset + fragment.BlockSize();
|
| } else {
|
| - DCHECK(IsEmptyFragment(ConstraintSpace().WritingMode(), *layout_result));
|
| + DCHECK(IsEmptyFragment(ConstraintSpace().WritingMode(), layout_result));
|
|
|
| child_end_bfc_block_offset = previous_inflow_position.bfc_block_offset;
|
| logical_block_offset = previous_inflow_position.logical_block_offset;
|
| @@ -613,8 +622,10 @@ NGBlockLayoutAlgorithm::FinishChildLayout(
|
| logical_block_offset = LayoutUnit();
|
| }
|
|
|
| - return NGPreviousInflowPosition{child_end_bfc_block_offset,
|
| - logical_block_offset, margin_strut};
|
| + NGMarginStrut margin_strut = layout_result.EndMarginStrut();
|
| + margin_strut.Append(child_data.margins.block_end);
|
| +
|
| + return {child_end_bfc_block_offset, logical_block_offset, margin_strut};
|
| }
|
|
|
| bool NGBlockLayoutAlgorithm::PositionNewFc(
|
|
|