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 b5244aa219ed18018f65de5b394879bce76674e3..64b252dd5455c6a3143da6fb3a8b188741a36344 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 |
@@ -61,25 +61,21 @@ bool IsOutOfSpace(const NGConstraintSpace& space, LayoutUnit content_size) { |
content_size >= space.FragmentainerSpaceAvailable(); |
} |
+bool IsEmptyFragment(NGWritingMode writing_mode, |
+ const NGLayoutResult& layout_result) { |
+ if (!layout_result.PhysicalFragment()) |
+ return true; |
+ |
+ NGFragment fragment(writing_mode, layout_result.PhysicalFragment().Get()); |
+ if (!fragment.BlockSize()) |
+ return true; |
+ |
+ return false; |
+} |
+ |
} // namespace |
-// This struct is used for communicating to a child the position of the |
-// previous inflow child. |
-struct NGPreviousInflowPosition { |
- LayoutUnit bfc_block_offset; |
- LayoutUnit logical_block_offset; |
- NGMarginStrut margin_strut; |
-}; |
- |
-// This strut holds information for the current inflow child. The data is not |
-// useful outside of handling this single inflow child. |
-struct NGInflowChildData { |
- NGLogicalOffset bfc_offset_estimate; |
- NGMarginStrut margin_strut; |
- NGBoxStrut margins; |
-}; |
- |
-void MaybeUpdateFragmentBfcOffset(const NGConstraintSpace& space, |
+bool MaybeUpdateFragmentBfcOffset(const NGConstraintSpace& space, |
LayoutUnit bfc_block_offset, |
NGFragmentBuilder* builder) { |
DCHECK(builder); |
@@ -88,24 +84,31 @@ void MaybeUpdateFragmentBfcOffset(const NGConstraintSpace& space, |
bfc_block_offset}; |
AdjustToClearance(space.ClearanceOffset(), &bfc_offset); |
builder->SetBfcOffset(bfc_offset); |
+ return true; |
} |
+ |
+ return false; |
} |
-void PositionPendingFloats(LayoutUnit origin_block_offset, |
- NGFragmentBuilder* container_builder, |
- NGConstraintSpace* space) { |
- DCHECK(container_builder->BfcOffset()) |
+void PositionPendingFloats( |
+ LayoutUnit origin_block_offset, |
+ NGFragmentBuilder* container_builder, |
+ Vector<RefPtr<NGUnpositionedFloat>>* unpositioned_floats, |
+ NGConstraintSpace* space) { |
+ DCHECK(container_builder->BfcOffset() || space->FloatsBfcOffset()) |
<< "Parent BFC offset should be known here"; |
+ LayoutUnit from_block_offset = |
+ container_builder->BfcOffset() |
+ ? container_builder->BfcOffset().value().block_offset |
+ : space->FloatsBfcOffset().value().block_offset; |
- const auto& unpositioned_floats = container_builder->UnpositionedFloats(); |
const auto positioned_floats = PositionFloats( |
- origin_block_offset, container_builder->BfcOffset().value().block_offset, |
- unpositioned_floats, space); |
+ origin_block_offset, from_block_offset, *unpositioned_floats, space); |
for (const auto& positioned_float : positioned_floats) |
container_builder->AddPositionedFloat(positioned_float); |
- container_builder->MutableUnpositionedFloats().clear(); |
+ unpositioned_floats->clear(); |
} |
NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm(NGBlockNode node, |
@@ -199,8 +202,14 @@ RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { |
container_builder_.SetDirection(constraint_space_->Direction()); |
container_builder_.SetWritingMode(constraint_space_->WritingMode()); |
container_builder_.SetSize(size); |
- container_builder_.MutableUnpositionedFloats() = |
- constraint_space_->UnpositionedFloats(); |
+ |
+ // If we have a list of unpositioned floats as input to this layout, we'll |
+ // need to abort once our BFC offset is resolved. Additionally the |
+ // FloatsBfcOffset() must not be present in this case. |
+ unpositioned_floats_ = constraint_space_->UnpositionedFloats(); |
+ abort_when_bfc_resolved_ = !unpositioned_floats_.IsEmpty(); |
+ if (abort_when_bfc_resolved_) |
+ DCHECK(!constraint_space_->FloatsBfcOffset()); |
NGBlockChildIterator child_iterator(Node().FirstChild(), BreakToken()); |
NGBlockChildIterator::Entry entry = child_iterator.NextChild(); |
@@ -221,8 +230,14 @@ RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { |
// border/padding between them. |
if (border_scrollbar_padding_.block_start) { |
input_bfc_block_offset += input_margin_strut.Sum(); |
- MaybeUpdateFragmentBfcOffset(ConstraintSpace(), input_bfc_block_offset, |
- &container_builder_); |
+ bool updated = MaybeUpdateFragmentBfcOffset( |
+ ConstraintSpace(), input_bfc_block_offset, &container_builder_); |
+ |
+ if (updated && abort_when_bfc_resolved_) { |
+ container_builder_.SwapUnpositionedFloats(&unpositioned_floats_); |
+ return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved); |
+ } |
+ |
// We reset the block offset here as it may have been effected by clearance. |
input_bfc_block_offset = ContainerBfcOffset().block_offset; |
input_margin_strut = NGMarginStrut(); |
@@ -242,26 +257,56 @@ RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { |
input_bfc_block_offset += content_size_; |
- NGPreviousInflowPosition previous_inflow_position = { |
- input_bfc_block_offset, content_size_, input_margin_strut}; |
+ WTF::Optional<NGPreviousInflowPosition> previous_inflow_position = |
+ NGPreviousInflowPosition{input_bfc_block_offset, content_size_, |
+ input_margin_strut}; |
while (child) { |
if (child.IsOutOfFlowPositioned()) { |
DCHECK(!child_break_token); |
- HandleOutOfFlowPositioned(previous_inflow_position, ToNGBlockNode(child)); |
+ HandleOutOfFlowPositioned(previous_inflow_position.value(), |
+ ToNGBlockNode(child)); |
} else if (child.IsFloating()) { |
- HandleFloating(previous_inflow_position, ToNGBlockNode(child), |
+ HandleFloating(previous_inflow_position.value(), ToNGBlockNode(child), |
ToNGBlockBreakToken(child_break_token)); |
} else { |
- NGInflowChildData child_data = |
- PrepareChildLayout(previous_inflow_position, child); |
+ // 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); |
+ CreateConstraintSpaceForChild(child, child_data.value()); |
RefPtr<NGLayoutResult> layout_result = |
child.Layout(child_space.Get(), child_break_token); |
- previous_inflow_position = |
- FinishChildLayout(*child_space, previous_inflow_position, child_data, |
- child, layout_result.Get()); |
+ |
+ // 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 = 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 (!previous_inflow_position) { |
+ container_builder_.SwapUnpositionedFloats(&unpositioned_floats_); |
+ return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved); |
+ } |
} |
entry = child_iterator.NextChild(); |
@@ -272,8 +317,8 @@ RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { |
break; |
} |
- NGMarginStrut end_margin_strut = previous_inflow_position.margin_strut; |
- LayoutUnit end_bfc_block_offset = previous_inflow_position.bfc_block_offset; |
+ NGMarginStrut end_margin_strut = previous_inflow_position->margin_strut; |
+ LayoutUnit end_bfc_block_offset = previous_inflow_position->bfc_block_offset; |
// Margins collapsing: |
// Bottom margins of an in-flow block box doesn't collapse with its last |
@@ -282,7 +327,7 @@ RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { |
if (border_scrollbar_padding_.block_end || |
ConstraintSpace().IsNewFormattingContext()) { |
content_size_ = |
- std::max(content_size_, previous_inflow_position.logical_block_offset + |
+ std::max(content_size_, previous_inflow_position->logical_block_offset + |
end_margin_strut.Sum()); |
end_margin_strut = NGMarginStrut(); |
} |
@@ -306,17 +351,20 @@ RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { |
ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); |
container_builder_.SetBlockSize(size.block_size); |
- // Layout our absolute and fixed positioned children. |
- NGOutOfFlowLayoutPart(ConstraintSpace(), Style(), &container_builder_).Run(); |
- |
// Non-empty blocks always know their position in space. |
// TODO(ikilpatrick): This check for a break token seems error prone. |
if (size.block_size || BreakToken()) { |
end_bfc_block_offset += end_margin_strut.Sum(); |
- MaybeUpdateFragmentBfcOffset(ConstraintSpace(), end_bfc_block_offset, |
- &container_builder_); |
+ bool updated = MaybeUpdateFragmentBfcOffset( |
+ ConstraintSpace(), end_bfc_block_offset, &container_builder_); |
+ |
+ if (updated && abort_when_bfc_resolved_) { |
+ container_builder_.SwapUnpositionedFloats(&unpositioned_floats_); |
+ return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved); |
+ } |
+ |
PositionPendingFloats(end_bfc_block_offset, &container_builder_, |
- MutableConstraintSpace()); |
+ &unpositioned_floats_, MutableConstraintSpace()); |
} |
// Margins collapsing: |
@@ -337,6 +385,20 @@ RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { |
ConstraintSpace().HasBlockFragmentation()) |
FinalizeForFragmentation(); |
+ // Only layout absolute and fixed children if we aren't going to revisit this |
+ // layout. |
+ if (unpositioned_floats_.IsEmpty()) { |
+ NGOutOfFlowLayoutPart(ConstraintSpace(), Style(), &container_builder_) |
+ .Run(); |
+ } |
+ |
+ // If we have any unpositioned floats at this stage, need to tell our parent |
+ // about this, so that we get relayout with a forced BFC offset. |
+ if (!unpositioned_floats_.IsEmpty()) { |
+ DCHECK(!container_builder_.BfcOffset()); |
+ container_builder_.SwapUnpositionedFloats(&unpositioned_floats_); |
+ } |
+ |
PropagateBaselinesFromChildren(); |
return container_builder_.ToBoxFragment(); |
@@ -372,26 +434,28 @@ void NGBlockLayoutAlgorithm::HandleFloating( |
RefPtr<NGUnpositionedFloat> unpositioned_float = NGUnpositionedFloat::Create( |
child_available_size_, child_percentage_size_, origin_inline_offset, |
constraint_space_->BfcOffset().inline_offset, margins, child, token); |
- container_builder_.AddUnpositionedFloat(unpositioned_float); |
+ unpositioned_floats_.push_back(std::move(unpositioned_float)); |
// If there is a break token for a float we must be resuming layout, we must |
// always know our position in the BFC. |
DCHECK(!token || container_builder_.BfcOffset()); |
// No need to postpone the positioning if we know the correct offset. |
- if (container_builder_.BfcOffset()) { |
+ if (container_builder_.BfcOffset() || ConstraintSpace().FloatsBfcOffset()) { |
// Adjust origin point to the margins of the last child. |
// Example: <div style="margin-bottom: 20px"><float></div> |
// <div style="margin-bottom: 30px"></div> |
LayoutUnit origin_block_offset = |
- previous_inflow_position.bfc_block_offset + |
- previous_inflow_position.margin_strut.Sum(); |
+ container_builder_.BfcOffset() |
+ ? previous_inflow_position.bfc_block_offset + |
+ previous_inflow_position.margin_strut.Sum() |
+ : ConstraintSpace().FloatsBfcOffset().value().block_offset; |
PositionPendingFloats(origin_block_offset, &container_builder_, |
- MutableConstraintSpace()); |
+ &unpositioned_floats_, MutableConstraintSpace()); |
} |
} |
-NGInflowChildData NGBlockLayoutAlgorithm::PrepareChildLayout( |
+WTF::Optional<NGInflowChildData> NGBlockLayoutAlgorithm::PrepareChildLayout( |
const NGPreviousInflowPosition& previous_inflow_position, |
NGLayoutInputNode child) { |
DCHECK(child); |
@@ -405,8 +469,7 @@ NGInflowChildData NGBlockLayoutAlgorithm::PrepareChildLayout( |
bool should_position_pending_floats = |
!child.CreatesNewFormattingContext() && |
- ClearanceMayAffectLayout(ConstraintSpace(), |
- container_builder_.UnpositionedFloats(), |
+ ClearanceMayAffectLayout(ConstraintSpace(), unpositioned_floats_, |
child.Style()); |
// Children which may clear a float need to force all the pending floats to |
@@ -414,12 +477,16 @@ NGInflowChildData NGBlockLayoutAlgorithm::PrepareChildLayout( |
if (should_position_pending_floats) { |
LayoutUnit origin_point_block_offset = |
bfc_block_offset + margin_strut.Sum(); |
- MaybeUpdateFragmentBfcOffset(ConstraintSpace(), origin_point_block_offset, |
- &container_builder_); |
+ bool updated = MaybeUpdateFragmentBfcOffset( |
+ ConstraintSpace(), origin_point_block_offset, &container_builder_); |
+ |
+ if (updated && abort_when_bfc_resolved_) |
+ return WTF::nullopt; |
+ |
// TODO(ikilpatrick): Check if origin_point_block_offset is correct - |
// MaybeUpdateFragmentBfcOffset might have changed it due to clearance. |
PositionPendingFloats(origin_point_block_offset, &container_builder_, |
- MutableConstraintSpace()); |
+ &unpositioned_floats_, MutableConstraintSpace()); |
} |
NGLogicalOffset child_bfc_offset = { |
@@ -429,41 +496,69 @@ NGInflowChildData NGBlockLayoutAlgorithm::PrepareChildLayout( |
// 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. |
+ // child's layout |
margin_strut.Append(margins.block_start); |
- return {child_bfc_offset, margin_strut, margins}; |
+ return NGInflowChildData{child_bfc_offset, margin_strut, margins}; |
} |
-NGPreviousInflowPosition NGBlockLayoutAlgorithm::FinishChildLayout( |
+WTF::Optional<NGPreviousInflowPosition> |
+NGBlockLayoutAlgorithm::FinishChildLayout( |
const NGConstraintSpace& child_space, |
const NGPreviousInflowPosition& previous_inflow_position, |
const NGInflowChildData& child_data, |
- const NGLayoutInputNode child, |
- 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()); |
- |
- NGBoxFragment fragment( |
- ConstraintSpace().WritingMode(), |
- ToNGPhysicalBoxFragment(layout_result->PhysicalFragment().Get())); |
+ 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. |
+ |
+ // If we don't know our BFC offset yet, we need to copy the list of |
+ // unpositioned floats from the child's layout result. |
+ // |
+ // If the child had any unpositioned floats, we need to abort our layout if |
+ // we resolve our BFC offset. |
+ // |
+ // If we are a new formatting context, the child will get re-laid out once it |
+ // has been positioned. |
+ // |
+ // 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()) { |
+ unpositioned_floats_ = layout_result->UnpositionedFloats(); |
+ abort_when_bfc_resolved_ |= !layout_result->UnpositionedFloats().IsEmpty(); |
+ if (child_space.FloatsBfcOffset()) |
+ DCHECK(layout_result->UnpositionedFloats().IsEmpty()); |
+ } |
// Determine the fragment's position in the parent space. |
WTF::Optional<NGLogicalOffset> child_bfc_offset; |
- if (child.CreatesNewFormattingContext()) |
- child_bfc_offset = PositionNewFc(child, previous_inflow_position, fragment, |
- child_data, child_space); |
- else if (layout_result->BfcOffset()) |
- child_bfc_offset = |
- PositionWithBfcOffset(layout_result->BfcOffset().value()); |
- else if (container_builder_.BfcOffset()) |
+ if (child.CreatesNewFormattingContext()) { |
+ if (!PositionNewFc(child, previous_inflow_position, *layout_result, |
+ child_data, child_space, &child_bfc_offset)) |
+ return WTF::nullopt; |
+ } else if (layout_result->BfcOffset()) { |
+ if (!PositionWithBfcOffset(layout_result->BfcOffset().value(), |
+ &child_bfc_offset)) |
+ return WTF::nullopt; |
+ } else if (container_builder_.BfcOffset()) { |
child_bfc_offset = |
PositionWithParentBfc(child_space, child_data, *layout_result); |
- else |
- DCHECK(!fragment.BlockSize()); |
+ } else |
+ DCHECK(IsEmptyFragment(ConstraintSpace().WritingMode(), *layout_result)); |
+ |
+ 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); |
+ } |
+ |
+ NGBoxFragment fragment( |
+ ConstraintSpace().WritingMode(), |
+ ToNGPhysicalBoxFragment(layout_result->PhysicalFragment().Get())); |
NGLogicalOffset logical_offset = |
CalculateLogicalOffset(child_data.margins, child_bfc_offset); |
@@ -471,6 +566,9 @@ NGPreviousInflowPosition NGBlockLayoutAlgorithm::FinishChildLayout( |
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: |
@@ -478,14 +576,19 @@ NGPreviousInflowPosition NGBlockLayoutAlgorithm::FinishChildLayout( |
// <div style="margin-top: 8px"></div> |
// <div style="margin-top: 10px"></div> |
// </div> |
- 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) { |
+ 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); |
// Determine the child's end BFC block offset and logical offset, for the |
// next child to use. |
@@ -495,12 +598,13 @@ NGPreviousInflowPosition 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.BlockSize() || layout_result->BfcOffset()) { |
+ if (fragment && (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_EQ(LayoutUnit(), fragment.BlockSize()); |
+ 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; |
} |
@@ -509,17 +613,23 @@ NGPreviousInflowPosition NGBlockLayoutAlgorithm::FinishChildLayout( |
logical_block_offset = LayoutUnit(); |
} |
- return {child_end_bfc_block_offset, logical_block_offset, margin_strut}; |
+ return NGPreviousInflowPosition{child_end_bfc_block_offset, |
+ logical_block_offset, margin_strut}; |
} |
-NGLogicalOffset NGBlockLayoutAlgorithm::PositionNewFc( |
+bool NGBlockLayoutAlgorithm::PositionNewFc( |
const NGLayoutInputNode& child, |
const NGPreviousInflowPosition& previous_inflow_position, |
- const NGBoxFragment& fragment, |
+ const NGLayoutResult& layout_result, |
const NGInflowChildData& child_data, |
- const NGConstraintSpace& child_space) { |
+ const NGConstraintSpace& child_space, |
+ WTF::Optional<NGLogicalOffset>* child_bfc_offset) { |
const ComputedStyle& child_style = child.Style(); |
+ NGBoxFragment fragment( |
+ ConstraintSpace().WritingMode(), |
+ ToNGPhysicalBoxFragment(layout_result.PhysicalFragment().Get())); |
+ |
LayoutUnit child_bfc_offset_estimate = |
child_data.bfc_offset_estimate.block_offset; |
@@ -529,7 +639,7 @@ NGLogicalOffset NGBlockLayoutAlgorithm::PositionNewFc( |
.SetIsNewFormattingContext(false) |
.ToConstraintSpace(child_space.WritingMode()); |
PositionFloats(child_bfc_offset_estimate, child_bfc_offset_estimate, |
- container_builder_.UnpositionedFloats(), tmp_space.Get()); |
+ unpositioned_floats_, tmp_space.Get()); |
NGLogicalOffset origin_offset = {ConstraintSpace().BfcOffset().inline_offset + |
border_scrollbar_padding_.inline_start, |
@@ -553,10 +663,14 @@ NGLogicalOffset NGBlockLayoutAlgorithm::PositionNewFc( |
child_bfc_offset_estimate += margin_strut.Sum(); |
// 4. The child's BFC block offset is known here. |
- MaybeUpdateFragmentBfcOffset(ConstraintSpace(), child_bfc_offset_estimate, |
- &container_builder_); |
+ bool updated = MaybeUpdateFragmentBfcOffset( |
+ ConstraintSpace(), child_bfc_offset_estimate, &container_builder_); |
+ |
+ if (updated && abort_when_bfc_resolved_) |
+ return false; |
+ |
PositionPendingFloats(child_bfc_offset_estimate, &container_builder_, |
- MutableConstraintSpace()); |
+ &unpositioned_floats_, MutableConstraintSpace()); |
origin_offset = {ConstraintSpace().BfcOffset().inline_offset + |
border_scrollbar_padding_.inline_start, |
@@ -571,17 +685,25 @@ NGLogicalOffset NGBlockLayoutAlgorithm::PositionNewFc( |
MutableConstraintSpace()->Exclusions().get(), child_space.AvailableSize(), |
origin_offset, child_data.margins, fragment.Size()); |
- return opportunity.offset; |
+ *child_bfc_offset = opportunity.offset; |
+ return true; |
} |
-NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithBfcOffset( |
- const NGLogicalOffset& bfc_offset) { |
+bool NGBlockLayoutAlgorithm::PositionWithBfcOffset( |
+ const NGLogicalOffset& bfc_offset, |
+ WTF::Optional<NGLogicalOffset>* child_bfc_offset) { |
LayoutUnit bfc_block_offset = bfc_offset.block_offset; |
- MaybeUpdateFragmentBfcOffset(ConstraintSpace(), bfc_block_offset, |
- &container_builder_); |
+ bool updated = MaybeUpdateFragmentBfcOffset( |
+ ConstraintSpace(), bfc_block_offset, &container_builder_); |
+ |
+ if (updated && abort_when_bfc_resolved_) |
+ return false; |
+ |
PositionPendingFloats(bfc_block_offset, &container_builder_, |
- MutableConstraintSpace()); |
- return bfc_offset; |
+ &unpositioned_floats_, MutableConstraintSpace()); |
+ |
+ *child_bfc_offset = bfc_offset; |
+ return true; |
} |
NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithParentBfc( |
@@ -590,9 +712,7 @@ NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithParentBfc( |
const NGLayoutResult& layout_result) { |
// The child must be an in-flow zero-block-size fragment, use its end margin |
// strut for positioning. |
- NGFragment fragment(ConstraintSpace().WritingMode(), |
- layout_result.PhysicalFragment().Get()); |
- DCHECK_EQ(fragment.BlockSize(), LayoutUnit()); |
+ DCHECK(IsEmptyFragment(ConstraintSpace().WritingMode(), layout_result)); |
NGLogicalOffset child_bfc_offset = { |
ConstraintSpace().BfcOffset().inline_offset + |
@@ -602,8 +722,6 @@ NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithParentBfc( |
layout_result.EndMarginStrut().Sum()}; |
AdjustToClearance(space.ClearanceOffset(), &child_bfc_offset); |
- PositionPendingFloats(child_bfc_offset.block_offset, &container_builder_, |
- MutableConstraintSpace()); |
return child_bfc_offset; |
} |
@@ -676,7 +794,8 @@ NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins(NGLayoutInputNode child) { |
RefPtr<NGConstraintSpace> NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild( |
const NGLayoutInputNode child, |
- const NGInflowChildData& child_data) { |
+ const NGInflowChildData& child_data, |
+ const WTF::Optional<NGLogicalOffset> floats_bfc_offset) { |
NGConstraintSpaceBuilder space_builder(MutableConstraintSpace()); |
space_builder.SetAvailableSize(child_available_size_) |
.SetPercentageResolutionSize(child_percentage_size_); |
@@ -689,11 +808,17 @@ RefPtr<NGConstraintSpace> NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild( |
.SetBfcOffset(child_data.bfc_offset_estimate) |
.SetMarginStrut(child_data.margin_strut); |
- if (!is_new_fc) { |
- // This clears the current layout's unpositioned floats as they may be |
- // positioned by the child. |
- space_builder.SetUnpositionedFloats( |
- container_builder_.MutableUnpositionedFloats()); |
+ if (!container_builder_.BfcOffset() && ConstraintSpace().FloatsBfcOffset()) { |
+ space_builder.SetFloatsBfcOffset( |
+ NGLogicalOffset{child_data.bfc_offset_estimate.inline_offset, |
+ ConstraintSpace().FloatsBfcOffset()->block_offset}); |
+ } |
+ |
+ if (floats_bfc_offset) |
+ space_builder.SetFloatsBfcOffset(floats_bfc_offset); |
+ |
+ if (!is_new_fc && !floats_bfc_offset) { |
+ space_builder.SetUnpositionedFloats(unpositioned_floats_); |
} |
if (child.IsInline()) { |
@@ -773,4 +898,5 @@ void NGBlockLayoutAlgorithm::PropagateBaselinesFromChildren() { |
} |
} |
} |
+ |
} // namespace blink |