| 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 f7f23b06477d3b8f328b98a8ae5743780c1f76dd..e4f148ad47b744dc0ff123f04fbb55dd2f2b188d 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
|
| @@ -7,7 +7,6 @@
|
| #include "core/layout/ng/inline/ng_inline_node.h"
|
| #include "core/layout/ng/ng_absolute_utils.h"
|
| #include "core/layout/ng/ng_block_child_iterator.h"
|
| -#include "core/layout/ng/ng_box_fragment.h"
|
| #include "core/layout/ng/ng_constraint_space.h"
|
| #include "core/layout/ng/ng_constraint_space_builder.h"
|
| #include "core/layout/ng/ng_floats_utils.h"
|
| @@ -84,6 +83,19 @@ void MaybeUpdateFragmentBfcOffset(const NGConstraintSpace& space,
|
| }
|
| }
|
|
|
| +void PositionPendingFloats(LayoutUnit origin_block_offset,
|
| + NGFragmentBuilder* container_builder,
|
| + NGConstraintSpace* space) {
|
| + DCHECK(container_builder->BfcOffset())
|
| + << "Parent BFC offset should be known here";
|
| + const auto& floating_objects = container_builder->UnpositionedFloats();
|
| + PositionFloats(origin_block_offset,
|
| + container_builder->BfcOffset().value().block_offset,
|
| + floating_objects, space);
|
| + container_builder->MutablePositionedFloats().AppendVector(floating_objects);
|
| + container_builder->MutableUnpositionedFloats().clear();
|
| +}
|
| +
|
| NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm(NGBlockNode* node,
|
| NGConstraintSpace* space,
|
| NGBlockBreakToken* break_token)
|
| @@ -130,14 +142,11 @@ Optional<MinMaxContentSize> NGBlockLayoutAlgorithm::ComputeMinMaxContentSize()
|
|
|
| NGLogicalOffset NGBlockLayoutAlgorithm::CalculateLogicalOffset(
|
| const WTF::Optional<NGLogicalOffset>& known_fragment_offset) {
|
| + if (known_fragment_offset)
|
| + return known_fragment_offset.value() - ContainerBfcOffset();
|
| LayoutUnit inline_offset =
|
| border_and_padding_.inline_start + curr_child_margins_.inline_start;
|
| - LayoutUnit block_offset = content_size_;
|
| - if (known_fragment_offset) {
|
| - block_offset = known_fragment_offset.value().block_offset -
|
| - ContainerBfcOffset().block_offset;
|
| - }
|
| - return {inline_offset, block_offset};
|
| + return {inline_offset, content_size_};
|
| }
|
|
|
| RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
|
| @@ -221,13 +230,16 @@ RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
|
| }
|
| }
|
|
|
| - PrepareChildLayout(child);
|
| + NGLogicalOffset child_bfc_offset = PrepareChildLayout(child);
|
| RefPtr<NGConstraintSpace> child_space =
|
| - CreateConstraintSpaceForChild(child);
|
| + CreateConstraintSpaceForChild(child_bfc_offset, child);
|
| RefPtr<NGLayoutResult> layout_result =
|
| child->Layout(child_space.Get(), child_break_token);
|
|
|
| - FinishChildLayout(child, child_space.Get(), layout_result);
|
| + if (child->IsFloating())
|
| + FinishFloatChildLayout(child->Style(), *child_space, layout_result.Get());
|
| + else
|
| + FinishChildLayout(child_space.Get(), layout_result.Get());
|
|
|
| entry = child_iterator.NextChild();
|
| child = entry.node;
|
| @@ -261,8 +273,8 @@ RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
|
| curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
|
| MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_,
|
| &container_builder_);
|
| - PositionPendingFloats(curr_bfc_offset_.block_offset,
|
| - MutableConstraintSpace(), &container_builder_);
|
| + PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_,
|
| + MutableConstraintSpace());
|
| }
|
|
|
| // Margins collapsing:
|
| @@ -283,25 +295,22 @@ RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
|
| return container_builder_.ToBoxFragment();
|
| }
|
|
|
| -void NGBlockLayoutAlgorithm::PrepareChildLayout(NGLayoutInputNode* child) {
|
| +NGLogicalOffset NGBlockLayoutAlgorithm::PrepareChildLayout(
|
| + NGLayoutInputNode* child) {
|
| DCHECK(child);
|
|
|
| - // Calculate margins in parent's writing mode.
|
| - curr_child_margins_ = CalculateMargins(
|
| - child, *space_builder_.ToConstraintSpace(
|
| - FromPlatformWritingMode(Style().GetWritingMode())));
|
| -
|
| - // Set estimated BFC offset to the next child's constraint space.
|
| curr_bfc_offset_ = container_builder_.BfcOffset()
|
| ? container_builder_.BfcOffset().value()
|
| : ConstraintSpace().BfcOffset();
|
| curr_bfc_offset_.block_offset += content_size_;
|
| - curr_bfc_offset_.inline_offset += border_and_padding_.inline_start;
|
|
|
| - bool is_floating = child->IsBlock() && child->Style().IsFloating();
|
| + // Calculate margins in parent's writing mode.
|
| + curr_child_margins_ = CalculateMargins(
|
| + child, *space_builder_.ToConstraintSpace(
|
| + FromPlatformWritingMode(Style().GetWritingMode())));
|
|
|
| bool should_position_pending_floats =
|
| - child->IsBlock() && !is_floating &&
|
| + !child->IsFloating() &&
|
| !IsNewFormattingContextForBlockLevelChild(Style(), *child) &&
|
| ClearanceMayAffectLayout(ConstraintSpace(),
|
| container_builder_.UnpositionedFloats(),
|
| @@ -316,106 +325,61 @@ void NGBlockLayoutAlgorithm::PrepareChildLayout(NGLayoutInputNode* child) {
|
| ConstraintSpace(),
|
| {curr_bfc_offset_.inline_offset, origin_point_block_offset},
|
| &container_builder_);
|
| - PositionPendingFloats(origin_point_block_offset, MutableConstraintSpace(),
|
| - &container_builder_);
|
| + PositionPendingFloats(origin_point_block_offset, &container_builder_,
|
| + MutableConstraintSpace());
|
| }
|
|
|
| - bool is_inflow = child->IsInline() || !is_floating;
|
| + bool is_inflow = child->IsInline() || !child->IsFloating();
|
|
|
| + NGLogicalOffset child_bfc_offset = curr_bfc_offset_;
|
| + child_bfc_offset.inline_offset += border_and_padding_.inline_start;
|
| // Only inflow children (e.g. not floats) are included in the child's margin
|
| // strut as they do not participate in margin collapsing.
|
| if (is_inflow) {
|
| - curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start;
|
| + child_bfc_offset.inline_offset += curr_child_margins_.inline_start;
|
| // Append the current margin strut with child's block start margin.
|
| - // Non empty border/padding use cases are handled inside of the child's
|
| - // layout.
|
| - curr_margin_strut_.Append(curr_child_margins_.block_start);
|
| + // Non empty border/padding, and new FC use cases are handled inside of the
|
| + // child's layout.
|
| + if (!IsNewFormattingContextForBlockLevelChild(Style(), *child))
|
| + curr_margin_strut_.Append(curr_child_margins_.block_start);
|
| }
|
|
|
| - // TODO(ikilpatrick): Children which establish new formatting contexts need
|
| - // to be placed using the opportunity iterator before we can collapse margins.
|
| - // If the child is placed at the block_start of this fragment, then its
|
| - // margins do impact the position of its parent, if not (its placed below a
|
| - // float for example) it doesn't. \o/
|
| -
|
| - bool should_collapse_margins =
|
| - child->IsInline() ||
|
| - (!is_floating &&
|
| - IsNewFormattingContextForBlockLevelChild(Style(), *child));
|
| -
|
| - // Inline children or children which establish a block formatting context
|
| - // collapse margins and position themselves immediately as they need to know
|
| - // their BFC offset for fragmentation purposes.
|
| - if (should_collapse_margins) {
|
| + // Should collapse margins if inline.
|
| + if (child->IsInline()) {
|
| curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
|
| MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_,
|
| &container_builder_);
|
| - PositionPendingFloats(curr_bfc_offset_.block_offset,
|
| - MutableConstraintSpace(), &container_builder_);
|
| + PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_,
|
| + MutableConstraintSpace());
|
| curr_margin_strut_ = {};
|
| }
|
| + child_bfc_offset.block_offset = curr_bfc_offset_.block_offset;
|
| + return child_bfc_offset;
|
| }
|
|
|
| void NGBlockLayoutAlgorithm::FinishChildLayout(
|
| - NGLayoutInputNode* child,
|
| - NGConstraintSpace* child_space,
|
| - RefPtr<NGLayoutResult> layout_result) {
|
| - NGBoxFragment fragment(
|
| - ConstraintSpace().WritingMode(),
|
| - ToNGPhysicalBoxFragment(layout_result->PhysicalFragment().Get()));
|
| -
|
| + const NGConstraintSpace* child_space,
|
| + NGLayoutResult* layout_result) {
|
| // Pull out unpositioned floats to the current fragment. This may needed if
|
| // for example the child fragment could not position its floats because it's
|
| // empty and therefore couldn't determine its position in space.
|
| container_builder_.MutableUnpositionedFloats().AppendVector(
|
| layout_result->UnpositionedFloats());
|
|
|
| - if (child->IsBlock() && child->Style().IsFloating()) {
|
| - NGLogicalOffset origin_offset = constraint_space_->BfcOffset();
|
| - origin_offset.inline_offset += border_and_padding_.inline_start;
|
| - RefPtr<NGFloatingObject> floating_object = NGFloatingObject::Create(
|
| - child->Style(), child_space->WritingMode(),
|
| - child_space->AvailableSize(), origin_offset,
|
| - constraint_space_->BfcOffset(), curr_child_margins_,
|
| - layout_result->PhysicalFragment().Get());
|
| - container_builder_.AddUnpositionedFloat(floating_object);
|
| - // No need to postpone the positioning if we know the correct offset.
|
| - if (container_builder_.BfcOffset()) {
|
| - NGLogicalOffset origin_point = curr_bfc_offset_;
|
| - // Adjust origin point to the margins of the last child.
|
| - // Example: <div style="margin-bottom: 20px"><float></div>
|
| - // <div style="margin-bottom: 30px"></div>
|
| - origin_point.block_offset += curr_margin_strut_.Sum();
|
| - PositionPendingFloats(origin_point.block_offset, MutableConstraintSpace(),
|
| - &container_builder_);
|
| - }
|
| - return;
|
| - }
|
| + NGBoxFragment fragment(
|
| + ConstraintSpace().WritingMode(),
|
| + ToNGPhysicalBoxFragment(layout_result->PhysicalFragment().Get()));
|
|
|
| - // Determine the fragment's position in the parent space either by using
|
| - // content_size_ or known fragment's BFC offset.
|
| - WTF::Optional<NGLogicalOffset> bfc_offset;
|
| - if (child_space->IsNewFormattingContext()) {
|
| - bfc_offset = curr_bfc_offset_;
|
| - } else if (fragment.BfcOffset()) {
|
| - // Fragment that knows its offset can be used to set parent's BFC position.
|
| - curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset;
|
| - MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_,
|
| - &container_builder_);
|
| - PositionPendingFloats(curr_bfc_offset_.block_offset,
|
| - MutableConstraintSpace(), &container_builder_);
|
| - bfc_offset = curr_bfc_offset_;
|
| - } else if (container_builder_.BfcOffset()) {
|
| - // Fragment doesn't know its offset but we can still calculate its BFC
|
| - // position because the parent fragment's BFC is known.
|
| - // Example:
|
| - // BFC Offset is known here because of the padding.
|
| - // <div style="padding: 1px">
|
| - // <div id="empty-div" style="margins: 1px"></div>
|
| - bfc_offset = curr_bfc_offset_;
|
| - bfc_offset.value().block_offset += curr_margin_strut_.Sum();
|
| - }
|
| - NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset);
|
| + // Determine the fragment's position in the parent space.
|
| + WTF::Optional<NGLogicalOffset> child_bfc_offset;
|
| + if (child_space->IsNewFormattingContext())
|
| + child_bfc_offset = PositionNewFc(fragment, *child_space);
|
| + else if (fragment.BfcOffset())
|
| + child_bfc_offset = PositionWithBfcOffset(fragment);
|
| + else if (container_builder_.BfcOffset())
|
| + child_bfc_offset = PositionWithParentBfc();
|
| +
|
| + NGLogicalOffset logical_offset = CalculateLogicalOffset(child_bfc_offset);
|
|
|
| // Update margin strut.
|
| curr_margin_strut_ = fragment.EndMarginStrut();
|
| @@ -438,6 +402,88 @@ void NGBlockLayoutAlgorithm::FinishChildLayout(
|
| container_builder_.AddChild(layout_result, logical_offset);
|
| }
|
|
|
| +NGLogicalOffset NGBlockLayoutAlgorithm::PositionNewFc(
|
| + const NGBoxFragment& fragment,
|
| + const NGConstraintSpace& child_space) {
|
| + // 1. Position all pending floats to a temporary space.
|
| + RefPtr<NGConstraintSpace> tmp_space =
|
| + NGConstraintSpaceBuilder(&child_space)
|
| + .SetIsNewFormattingContext(false)
|
| + .ToConstraintSpace(child_space.WritingMode());
|
| + PositionFloats(curr_bfc_offset_.block_offset, curr_bfc_offset_.block_offset,
|
| + container_builder_.UnpositionedFloats(), tmp_space.Get());
|
| +
|
| + // 2. Find an estimated layout opportunity for our fragment.
|
| + NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment(
|
| + tmp_space->Exclusions().get(), child_space.AvailableSize(),
|
| + curr_bfc_offset_, curr_child_margins_, fragment);
|
| +
|
| + // 3. If the found opportunity lies on the same line with our estimated
|
| + // child's BFC offset then merge fragment's margins with the current
|
| + // MarginStrut.
|
| + if (opportunity.offset.block_offset == curr_bfc_offset_.block_offset)
|
| + curr_margin_strut_.Append(curr_child_margins_.block_start);
|
| + curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
|
| + curr_margin_strut_ = {};
|
| +
|
| + // 4. The child's BFC block offset is known here.
|
| + MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_,
|
| + &container_builder_);
|
| + PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_,
|
| + MutableConstraintSpace());
|
| +
|
| + // 5. Find the final layout opportunity for the fragment after all pending
|
| + // floats are positioned at the correct BFC block's offset.
|
| + opportunity = FindLayoutOpportunityForFragment(
|
| + MutableConstraintSpace()->Exclusions().get(), child_space.AvailableSize(),
|
| + curr_bfc_offset_, curr_child_margins_, fragment);
|
| +
|
| + curr_bfc_offset_ = opportunity.offset;
|
| + return curr_bfc_offset_;
|
| +}
|
| +
|
| +NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithBfcOffset(
|
| + const NGBoxFragment& fragment) {
|
| + DCHECK(fragment.BfcOffset());
|
| + curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset;
|
| + MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_,
|
| + &container_builder_);
|
| + PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_,
|
| + MutableConstraintSpace());
|
| + return fragment.BfcOffset().value();
|
| +}
|
| +
|
| +NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithParentBfc() {
|
| + curr_bfc_offset_ +=
|
| + {border_and_padding_.inline_start + curr_child_margins_.inline_start,
|
| + curr_margin_strut_.Sum()};
|
| + return curr_bfc_offset_;
|
| +}
|
| +
|
| +void NGBlockLayoutAlgorithm::FinishFloatChildLayout(
|
| + const ComputedStyle& child_style,
|
| + const NGConstraintSpace& child_space,
|
| + const NGLayoutResult* layout_result) {
|
| + NGLogicalOffset origin_offset = constraint_space_->BfcOffset();
|
| + origin_offset.inline_offset += border_and_padding_.inline_start;
|
| + RefPtr<NGFloatingObject> floating_object = NGFloatingObject::Create(
|
| + child_style, child_space.WritingMode(), child_space.AvailableSize(),
|
| + origin_offset, constraint_space_->BfcOffset(), curr_child_margins_,
|
| + layout_result->PhysicalFragment().Get());
|
| + container_builder_.AddUnpositionedFloat(floating_object);
|
| +
|
| + // No need to postpone the positioning if we know the correct offset.
|
| + if (container_builder_.BfcOffset()) {
|
| + NGLogicalOffset origin_point = curr_bfc_offset_;
|
| + // Adjust origin point to the margins of the last child.
|
| + // Example: <div style="margin-bottom: 20px"><float></div>
|
| + // <div style="margin-bottom: 30px"></div>
|
| + origin_point.block_offset += curr_margin_strut_.Sum();
|
| + PositionPendingFloats(origin_point.block_offset, &container_builder_,
|
| + MutableConstraintSpace());
|
| + }
|
| +}
|
| +
|
| void NGBlockLayoutAlgorithm::FinalizeForFragmentation() {
|
| LayoutUnit used_block_size =
|
| BreakToken() ? BreakToken()->UsedBlockSize() : LayoutUnit();
|
| @@ -480,6 +526,8 @@ NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins(
|
| NGLayoutInputNode* child,
|
| const NGConstraintSpace& space) {
|
| DCHECK(child);
|
| + if (child->IsInline())
|
| + return {};
|
| const ComputedStyle& child_style = child->Style();
|
|
|
| WTF::Optional<MinMaxContentSize> sizes;
|
| @@ -490,25 +538,25 @@ NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins(
|
| ComputeInlineSizeForFragment(space, child_style, sizes);
|
| NGBoxStrut margins = ComputeMargins(space, child_style, space.WritingMode(),
|
| space.Direction());
|
| - if (!child_style.IsFloating()) {
|
| + if (!child->IsFloating()) {
|
| ApplyAutoMargins(space, child_style, child_inline_size, &margins);
|
| }
|
| return margins;
|
| }
|
|
|
| RefPtr<NGConstraintSpace> NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
|
| + const NGLogicalOffset& child_bfc_offset,
|
| NGLayoutInputNode* child) {
|
| DCHECK(child);
|
|
|
| const ComputedStyle& child_style = child->Style();
|
| bool is_new_bfc = IsNewFormattingContextForBlockLevelChild(Style(), *child);
|
| space_builder_.SetIsNewFormattingContext(is_new_bfc)
|
| - .SetBfcOffset(curr_bfc_offset_);
|
| + .SetBfcOffset(child_bfc_offset);
|
|
|
| if (child->IsInline()) {
|
| // TODO(kojii): Setup space_builder_ appropriately for inline child.
|
| - space_builder_.SetBfcOffset(curr_bfc_offset_)
|
| - .SetClearanceOffset(ConstraintSpace().ClearanceOffset());
|
| + space_builder_.SetClearanceOffset(ConstraintSpace().ClearanceOffset());
|
| return space_builder_.ToConstraintSpace(
|
| FromPlatformWritingMode(Style().GetWritingMode()));
|
| }
|
| @@ -522,8 +570,8 @@ RefPtr<NGConstraintSpace> NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
|
| // Float's margins are not included in child's space because:
|
| // 1) Floats do not participate in margins collapsing.
|
| // 2) Floats margins are used separately to calculate floating exclusions.
|
| - space_builder_.SetMarginStrut(child_style.IsFloating() ? NGMarginStrut()
|
| - : curr_margin_strut_);
|
| + space_builder_.SetMarginStrut(child->IsFloating() ? NGMarginStrut()
|
| + : curr_margin_strut_);
|
|
|
| LayoutUnit space_available;
|
| if (constraint_space_->HasBlockFragmentation()) {
|
| @@ -532,7 +580,7 @@ RefPtr<NGConstraintSpace> NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
|
| // position in the formatting context, and are able to adjust the
|
| // fragmentation line.
|
| if (is_new_bfc) {
|
| - space_available -= curr_bfc_offset_.block_offset;
|
| + space_available -= child_bfc_offset.block_offset;
|
| }
|
| }
|
| space_builder_.SetFragmentainerSpaceAvailable(space_available);
|
|
|