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 e41fcf817a8203b5f30ff46d9b332f3fcb2ef371..b1cf146bd5d4314cc49cb1496ea09b07ea1114b4 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 |
@@ -6,7 +6,6 @@ |
#include "core/layout/ng/ng_absolute_utils.h" |
#include "core/layout/ng/ng_block_break_token.h" |
-#include "core/layout/ng/ng_box_fragment.h" |
#include "core/layout/ng/ng_column_mapper.h" |
#include "core/layout/ng/ng_constraint_space.h" |
#include "core/layout/ng/ng_constraint_space_builder.h" |
@@ -23,24 +22,39 @@ |
namespace blink { |
namespace { |
-// Adjusts content's offset to CSS "clear" property. |
-// TODO(glebl): Support margin collapsing edge cases, e.g. margin collapsing |
-// should not occur if "clear" is applied to non-floating blocks. |
-// TODO(layout-ng): the call to AdjustToClearance should be moved to |
-// CreateConstraintSpaceForChild once ConstraintSpaceBuilder is sharing the |
-// exclusion information between constraint spaces. |
-void AdjustToClearance(const NGConstraintSpace& space, |
+// Updates the fragment's BFC offset if it's not already set. |
+void UpdateFragmentBfcOffset(const NGLogicalOffset& offset, |
+ const NGConstraintSpace& space, |
+ NGFragmentBuilder* builder) { |
+ NGLogicalOffset fragment_offset = |
+ space.IsNewFormattingContext() ? NGLogicalOffset() : offset; |
+ if (!builder->BfcOffset()) |
+ builder->SetBfcOffset(fragment_offset); |
+} |
+ |
+// Adjusts content_size to respect the CSS "clear" property. |
+// Picks up the maximum between left/right exclusions and content_size depending |
+// on the value of style.clear() property. |
+void AdjustToClearance(const std::shared_ptr<NGExclusions>& exclusions, |
const ComputedStyle& style, |
+ const NGLogicalOffset& from_offset, |
LayoutUnit* content_size) { |
- const NGExclusion* right_exclusion = space.Exclusions()->last_right_float; |
- const NGExclusion* left_exclusion = space.Exclusions()->last_left_float; |
- |
- // Calculates Left/Right block end offset from left/right float exclusions or |
- // use the default content offset position. |
- LayoutUnit left_block_end_offset = |
- left_exclusion ? left_exclusion->rect.BlockEndOffset() : *content_size; |
- LayoutUnit right_block_end_offset = |
- right_exclusion ? right_exclusion->rect.BlockEndOffset() : *content_size; |
+ DCHECK(content_size) << "content_size cannot be null here"; |
+ const NGExclusion* right_exclusion = exclusions->last_right_float; |
+ const NGExclusion* left_exclusion = exclusions->last_left_float; |
+ |
+ LayoutUnit left_block_end_offset = *content_size; |
+ if (left_exclusion) { |
+ left_block_end_offset = std::max( |
+ left_exclusion->rect.BlockEndOffset() - from_offset.block_offset, |
+ *content_size); |
+ } |
+ LayoutUnit right_block_end_offset = *content_size; |
+ if (right_exclusion) { |
+ right_block_end_offset = std::max( |
+ right_exclusion->rect.BlockEndOffset() - from_offset.block_offset, |
+ *content_size); |
+ } |
switch (style.clear()) { |
case EClear::kNone: |
@@ -59,21 +73,12 @@ void AdjustToClearance(const NGConstraintSpace& space, |
} |
} |
-LayoutUnit ComputeCollapsedMarginBlockStart( |
- const NGDeprecatedMarginStrut& prev_margin_strut, |
- const NGDeprecatedMarginStrut& curr_margin_strut) { |
- return std::max(prev_margin_strut.margin_block_end, |
- curr_margin_strut.margin_block_start) - |
- std::max(prev_margin_strut.negative_margin_block_end.abs(), |
- curr_margin_strut.negative_margin_block_start.abs()); |
-} |
- |
// Creates an exclusion from the fragment that will be placed in the provided |
// layout opportunity. |
NGExclusion CreateExclusion(const NGFragment& fragment, |
const NGLayoutOpportunity& opportunity, |
- LayoutUnit float_offset, |
- NGBoxStrut margins, |
+ const LayoutUnit float_offset, |
+ const NGBoxStrut& margins, |
NGExclusion::Type exclusion_type) { |
NGExclusion exclusion; |
exclusion.type = exclusion_type; |
@@ -81,16 +86,30 @@ NGExclusion CreateExclusion(const NGFragment& fragment, |
rect.offset = opportunity.offset; |
rect.offset.inline_offset += float_offset; |
- rect.size.inline_size = fragment.InlineSize(); |
- rect.size.block_size = fragment.BlockSize(); |
- |
- // Adjust to child's margin. |
- rect.size.block_size += margins.BlockSum(); |
- rect.size.inline_size += margins.InlineSum(); |
- |
+ rect.size.inline_size = fragment.InlineSize() + margins.InlineSum(); |
+ rect.size.block_size = fragment.BlockSize() + margins.BlockSum(); |
return exclusion; |
} |
+// Adjusts the provided offset to the top edge alignment rule. |
+// Top edge alignment rule: the outer top of a floating box may not be higher |
+// than the outer top of any block or floated box generated by an element |
+// earlier in the source document. |
+NGLogicalOffset AdjustToTopEdgeAlignmentRule(const NGConstraintSpace& space, |
+ const NGLogicalOffset& offset) { |
+ NGLogicalOffset adjusted_offset = offset; |
+ LayoutUnit& adjusted_block_offset = adjusted_offset.block_offset; |
+ if (space.Exclusions()->last_left_float) |
+ adjusted_block_offset = |
+ std::max(adjusted_block_offset, |
+ space.Exclusions()->last_left_float->rect.BlockStartOffset()); |
+ if (space.Exclusions()->last_right_float) |
+ adjusted_block_offset = |
+ std::max(adjusted_block_offset, |
+ space.Exclusions()->last_right_float->rect.BlockStartOffset()); |
+ return adjusted_offset; |
+} |
+ |
// Finds a layout opportunity for the fragment. |
// It iterates over all layout opportunities in the constraint space and returns |
// the first layout opportunity that is wider than the fragment or returns the |
@@ -99,13 +118,21 @@ NGExclusion CreateExclusion(const NGFragment& fragment, |
// @param space Constraint space that is used to find layout opportunity for |
// the fragment. |
// @param fragment Fragment that needs to be placed. |
+// @param origin_point {@code space}'s offset relative to the space that |
+// establishes a new formatting context that we're currently |
+// in and where all our exclusions reside. |
// @param margins Margins of the fragment. |
// @return Layout opportunity for the fragment. |
const NGLayoutOpportunity FindLayoutOpportunityForFragment( |
NGConstraintSpace* space, |
const NGFragment& fragment, |
+ const NGLogicalOffset& origin_point, |
const NGBoxStrut& margins) { |
- NGLayoutOpportunityIterator* opportunity_iter = space->LayoutOpportunities(); |
+ NGLogicalOffset adjusted_origin_point = |
+ AdjustToTopEdgeAlignmentRule(*space, origin_point); |
+ |
+ NGLayoutOpportunityIterator* opportunity_iter = |
+ space->LayoutOpportunities(adjusted_origin_point); |
NGLayoutOpportunity opportunity; |
NGLayoutOpportunity opportunity_candidate = opportunity_iter->Next(); |
@@ -114,20 +141,19 @@ const NGLayoutOpportunity FindLayoutOpportunityForFragment( |
// Checking opportunity's block size is not necessary as a float cannot be |
// positioned on top of another float inside of the same constraint space. |
auto fragment_inline_size = fragment.InlineSize() + margins.InlineSum(); |
- if (opportunity.size.inline_size > fragment_inline_size) |
+ if (opportunity.size.inline_size >= fragment_inline_size) |
break; |
- |
opportunity_candidate = opportunity_iter->Next(); |
} |
- |
return opportunity; |
} |
// Calculates the logical offset for opportunity. |
NGLogicalOffset CalculateLogicalOffsetForOpportunity( |
const NGLayoutOpportunity& opportunity, |
- LayoutUnit float_offset, |
- NGBoxStrut margins) { |
+ const LayoutUnit float_offset, |
+ const NGBoxStrut& margins, |
+ const NGLogicalOffset& space_offset) { |
// Adjust to child's margin. |
LayoutUnit inline_offset = margins.inline_start; |
LayoutUnit block_offset = margins.block_start; |
@@ -138,9 +164,59 @@ NGLogicalOffset CalculateLogicalOffsetForOpportunity( |
inline_offset += float_offset; |
+ block_offset -= space_offset.block_offset; |
+ inline_offset -= space_offset.inline_offset; |
+ |
return NGLogicalOffset(inline_offset, block_offset); |
} |
+// Calculates the relative position from {@code from_offset} of the |
+// floating object that is requested to be positioned from {@code origin_point}. |
+NGLogicalOffset PositionFloat(const NGLogicalOffset& origin_point, |
+ const NGLogicalOffset& from_offset, |
+ NGFloatingObject* floating_object) { |
+ NGConstraintSpace* float_space = floating_object->space; |
+ DCHECK(floating_object->fragment) << "Fragment cannot be null here"; |
+ NGBoxFragment* float_fragment = |
+ new NGBoxFragment(float_space->WritingMode(), float_space->Direction(), |
+ toNGPhysicalBoxFragment(floating_object->fragment)); |
+ // Find a layout opportunity that will fit our float. |
+ const NGLayoutOpportunity opportunity = |
+ FindLayoutOpportunityForFragment(floating_object->space, *float_fragment, |
+ origin_point, floating_object->margins); |
+ DCHECK(!opportunity.IsEmpty()) << "Opportunity is empty but it shouldn't be"; |
+ |
+ // Calculate the float offset if needed. |
+ LayoutUnit float_offset; |
+ if (floating_object->exclusion_type == NGExclusion::kFloatRight) { |
+ float_offset = opportunity.size.inline_size - float_fragment->InlineSize(); |
+ } |
+ |
+ // Add the float as an exclusion. |
+ const NGExclusion exclusion = CreateExclusion( |
+ *float_fragment, opportunity, float_offset, floating_object->margins, |
+ floating_object->exclusion_type); |
+ float_space->AddExclusion(exclusion); |
+ |
+ return CalculateLogicalOffsetForOpportunity( |
+ opportunity, float_offset, floating_object->margins, from_offset); |
+} |
+ |
+// Positions pending floats stored on the fragment builder starting from |
+// {@code origin_point}. |
+void PositionPendingFloats(const NGLogicalOffset& origin_point, |
+ NGFragmentBuilder* builder) { |
+ DCHECK(builder->BfcOffset()) << "Parent BFC offset should be known here"; |
+ NGLogicalOffset from_offset = builder->BfcOffset().value(); |
+ |
+ for (auto& floating_object : builder->UnpositionedFloats()) { |
+ NGLogicalOffset float_fragment_offset = |
+ PositionFloat(origin_point, from_offset, floating_object); |
+ builder->AddFloatingObject(floating_object, float_fragment_offset); |
+ } |
+ builder->MutableUnpositionedFloats().clear(); |
+} |
+ |
// Whether an in-flow block-level child creates a new formatting context. |
// |
// This will *NOT* check the following cases: |
@@ -190,8 +266,7 @@ NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm( |
constraint_space_(constraint_space), |
break_token_(break_token), |
builder_(new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox, |
- layout_object)), |
- is_fragment_margin_strut_block_start_updated_(false) { |
+ layout_object)) { |
DCHECK(style_); |
} |
@@ -222,6 +297,18 @@ bool NGBlockLayoutAlgorithm::ComputeMinAndMaxContentSizes( |
return true; |
} |
+NGLogicalOffset NGBlockLayoutAlgorithm::CalculateRelativeOffset( |
+ const NGBoxFragment& fragment) { |
+ LayoutUnit inline_offset = |
+ border_and_padding_.inline_start + curr_child_margins_.inline_start; |
+ LayoutUnit block_offset = content_size_; |
+ if (fragment.BfcOffset()) { |
+ block_offset = fragment.BfcOffset().value().block_offset - |
+ builder_->BfcOffset().value().block_offset; |
+ } |
+ return {inline_offset, block_offset}; |
+} |
+ |
NGPhysicalFragment* NGBlockLayoutAlgorithm::Layout() { |
WTF::Optional<MinAndMaxContentSizes> sizes; |
if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style())) { |
@@ -268,6 +355,8 @@ NGPhysicalFragment* NGBlockLayoutAlgorithm::Layout() { |
builder_->SetWritingMode(constraint_space_->WritingMode()); |
builder_->SetInlineSize(inline_size).SetBlockSize(block_size); |
+ // TODO(glebl): fix multicol after the new margin collapsing/floats algorithm |
+ // based on BFCOffset is checked in. |
if (NGBlockBreakToken* token = CurrentBlockBreakToken()) { |
// Resume after a previous break. |
content_size_ = token->BreakOffset(); |
@@ -277,6 +366,19 @@ NGPhysicalFragment* NGBlockLayoutAlgorithm::Layout() { |
current_child_ = first_child_; |
} |
+ curr_margin_strut_ = ConstraintSpace().MarginStrut(); |
+ curr_bfc_offset_ = ConstraintSpace().BfcOffset(); |
+ |
+ // Margins collapsing: |
+ // Do not collapse margins between parent and its child if there is |
+ // border/padding between them. |
+ if (border_and_padding_.block_start) { |
+ curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
+ builder_->SetBfcOffset(curr_bfc_offset_); |
+ curr_margin_strut_ = NGMarginStrut(); |
+ } |
+ curr_bfc_offset_.block_offset += content_size_; |
+ |
while (current_child_) { |
EPosition position = current_child_->Style()->position(); |
if (position == AbsolutePosition || position == FixedPosition) { |
@@ -301,7 +403,16 @@ NGPhysicalFragment* NGBlockLayoutAlgorithm::Layout() { |
break; |
} |
+ // Margins collapsing: |
+ // Bottom margins of an in-flow block box doesn't collapse with its last |
+ // in-flow block-level child's bottom margin if the box has bottom |
+ // border/padding. |
content_size_ += border_and_padding_.block_end; |
+ if (border_and_padding_.block_end || |
+ ConstraintSpace().IsNewFormattingContext()) { |
+ content_size_ += curr_margin_strut_.Sum(); |
+ curr_margin_strut_ = NGMarginStrut(); |
+ } |
// Recompute the block-axis size now that we know our content size. |
block_size = |
@@ -311,6 +422,22 @@ NGPhysicalFragment* NGBlockLayoutAlgorithm::Layout() { |
// Layout our absolute and fixed positioned children. |
NGOutOfFlowLayoutPart(Style(), builder_).Run(); |
+ // Non empty blocks always know their position in space: |
+ if (block_size) { |
+ curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
+ UpdateFragmentBfcOffset(curr_bfc_offset_, ConstraintSpace(), builder_); |
+ PositionPendingFloats(curr_bfc_offset_, builder_); |
+ } |
+ |
+ // Margins collapsing: |
+ // Do not collapse margins between the last in-flow child and bottom margin |
+ // of its parent if the parent has height != auto() |
+ if (!Style().logicalHeight().isAuto()) { |
+ // TODO(glebl): handle minLogicalHeight, maxLogicalHeight. |
+ curr_margin_strut_ = NGMarginStrut(); |
+ } |
+ builder_->SetEndMarginStrut(curr_margin_strut_); |
+ |
builder_->SetInlineOverflow(max_inline_size_).SetBlockOverflow(content_size_); |
if (ConstraintSpace().HasBlockFragmentation()) |
@@ -321,23 +448,58 @@ NGPhysicalFragment* NGBlockLayoutAlgorithm::Layout() { |
return fragment; |
} |
-void NGBlockLayoutAlgorithm::FinishCurrentChildLayout(NGFragment* fragment) { |
- NGBoxStrut child_margins = ComputeMargins( |
- *space_for_current_child_, CurrentChildStyle(), |
- constraint_space_->WritingMode(), constraint_space_->Direction()); |
- NGLogicalOffset fragment_offset; |
+void NGBlockLayoutAlgorithm::FinishCurrentChildLayout( |
+ NGFragment* base_fragment) { |
+ const NGBoxFragment& fragment = *toNGBoxFragment(base_fragment); |
+ if (!fragment.PhysicalFragment()->UnpositionedFloats().isEmpty()) |
+ DCHECK(!builder_->BfcOffset()) << "Parent BFC offset shouldn't be set here"; |
+ // 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. |
+ builder_->MutableUnpositionedFloats().appendVector( |
+ fragment.PhysicalFragment()->UnpositionedFloats()); |
+ |
if (CurrentChildStyle().isFloating()) { |
- fragment_offset = PositionFloatFragment(*fragment, child_margins); |
- } else { |
- ApplyAutoMargins(*space_for_current_child_, CurrentChildStyle(), |
- fragment->InlineSize(), &child_margins); |
- fragment_offset = PositionFragment(*fragment, child_margins); |
+ NGFloatingObject* floating_object = new NGFloatingObject( |
+ fragment.PhysicalFragment(), space_for_current_child_, current_child_, |
+ CurrentChildStyle(), curr_child_margins_); |
+ builder_->AddUnpositionedFloat(floating_object); |
+ // No need to postpone the positioning if we know the correct offset. |
+ if (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, builder_); |
+ } |
+ return; |
+ } |
+ |
+ // Fragment that knows its offset can be used to set parent's BFC position. |
+ if (fragment.BfcOffset()) { |
+ curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset; |
+ UpdateFragmentBfcOffset(curr_bfc_offset_, ConstraintSpace(), builder_); |
+ PositionPendingFloats(curr_bfc_offset_, builder_); |
} |
+ NGLogicalOffset fragment_offset = CalculateRelativeOffset(fragment); |
+ |
if (fragmentainer_mapper_) |
fragmentainer_mapper_->ToVisualOffset(fragment_offset); |
else |
fragment_offset.block_offset -= PreviousBreakOffset(); |
- builder_->AddChild(fragment, fragment_offset); |
+ |
+ builder_->AddChild(base_fragment, fragment_offset); |
+ |
+ // Update margin strut. |
+ curr_margin_strut_ = fragment.EndMarginStrut(); |
+ curr_margin_strut_.Append(curr_child_margins_.block_end); |
+ |
+ content_size_ = fragment.BlockSize() + fragment_offset.block_offset; |
+ max_inline_size_ = |
+ std::max(max_inline_size_, fragment.InlineSize() + |
+ curr_child_margins_.InlineSum() + |
+ border_and_padding_.InlineSum()); |
} |
bool NGBlockLayoutAlgorithm::ProceedToNextUnfinishedSibling( |
@@ -480,133 +642,6 @@ LayoutUnit NGBlockLayoutAlgorithm::SpaceAvailableForCurrentChild() const { |
return space_left; |
} |
-NGBoxStrut NGBlockLayoutAlgorithm::CollapseMargins( |
- const NGBoxStrut& margins, |
- const NGBoxFragment& fragment) { |
- bool is_zero_height_box = !fragment.BlockSize() && margins.IsEmpty() && |
- fragment.MarginStrut().IsEmpty(); |
- // Create the current child's margin strut from its children's margin strut or |
- // use margin strut from the the last non-empty child. |
- NGDeprecatedMarginStrut curr_margin_strut = |
- is_zero_height_box ? prev_child_margin_strut_ : fragment.MarginStrut(); |
- |
- // Calculate borders and padding for the current child. |
- NGBoxStrut border_and_padding = |
- ComputeBorders(CurrentChildStyle()) + |
- ComputePadding(ConstraintSpace(), CurrentChildStyle()); |
- |
- // Collapse BLOCK-START margins if there is no padding or border between |
- // parent (current child) and its first in-flow child. |
- if (border_and_padding.block_start) { |
- curr_margin_strut.SetMarginBlockStart(margins.block_start); |
- } else { |
- curr_margin_strut.AppendMarginBlockStart(margins.block_start); |
- } |
- |
- // Collapse BLOCK-END margins if |
- // 1) there is no padding or border between parent (current child) and its |
- // first/last in-flow child |
- // 2) parent's logical height is auto. |
- if (CurrentChildStyle().logicalHeight().isAuto() && |
- !border_and_padding.block_end) { |
- curr_margin_strut.AppendMarginBlockEnd(margins.block_end); |
- } else { |
- curr_margin_strut.SetMarginBlockEnd(margins.block_end); |
- } |
- |
- NGBoxStrut result_margins; |
- // Margins of the newly established formatting context do not participate |
- // in Collapsing Margins: |
- // - Compute margins block start for adjoining blocks *including* 1st block. |
- // - Compute margins block end for the last block. |
- // - Do not set the computed margins to the parent fragment. |
- if (constraint_space_->IsNewFormattingContext()) { |
- result_margins.block_start = ComputeCollapsedMarginBlockStart( |
- prev_child_margin_strut_, curr_margin_strut); |
- bool is_last_child = !current_child_->NextSibling(); |
- if (is_last_child) |
- result_margins.block_end = curr_margin_strut.BlockEndSum(); |
- return result_margins; |
- } |
- |
- // Zero-height boxes are ignored and do not participate in margin collapsing. |
- if (is_zero_height_box) |
- return result_margins; |
- |
- // Compute the margin block start for adjoining blocks *excluding* 1st block |
- if (is_fragment_margin_strut_block_start_updated_) { |
- result_margins.block_start = ComputeCollapsedMarginBlockStart( |
- prev_child_margin_strut_, curr_margin_strut); |
- } |
- |
- // Update the parent fragment's margin strut |
- UpdateMarginStrut(curr_margin_strut); |
- |
- prev_child_margin_strut_ = curr_margin_strut; |
- return result_margins; |
-} |
- |
-NGLogicalOffset NGBlockLayoutAlgorithm::PositionFragment( |
- const NGFragment& fragment, |
- const NGBoxStrut& margins) { |
- const NGBoxStrut collapsed_margins = |
- CollapseMargins(margins, toNGBoxFragment(fragment)); |
- |
- AdjustToClearance(ConstraintSpace(), CurrentChildStyle(), &content_size_); |
- |
- LayoutUnit inline_offset = |
- border_and_padding_.inline_start + margins.inline_start; |
- LayoutUnit block_offset = content_size_ + collapsed_margins.block_start; |
- |
- content_size_ += fragment.BlockSize() + collapsed_margins.BlockSum(); |
- max_inline_size_ = |
- std::max(max_inline_size_, fragment.InlineSize() + margins.InlineSum() + |
- border_and_padding_.InlineSum()); |
- return NGLogicalOffset(inline_offset, block_offset); |
-} |
- |
-NGLogicalOffset NGBlockLayoutAlgorithm::PositionFloatFragment( |
- const NGFragment& fragment, |
- const NGBoxStrut& margins) { |
- // TODO(glebl@chromium.org): Support the top edge alignment rule. |
- // Find a layout opportunity that will fit our float. |
- |
- // Update offset if there is a clearance. |
- NGLogicalOffset offset = CurrentChildConstraintSpace().Offset(); |
- AdjustToClearance(ConstraintSpace(), CurrentChildStyle(), |
- &offset.block_offset); |
- space_for_current_child_->SetOffset(offset); |
- |
- const NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment( |
- space_for_current_child_, fragment, margins); |
- DCHECK(!opportunity.IsEmpty()) << "Opportunity is empty but it shouldn't be"; |
- |
- NGExclusion::Type exclusion_type = NGExclusion::kFloatLeft; |
- // Calculate the float offset if needed. |
- LayoutUnit float_offset; |
- if (CurrentChildStyle().floating() == EFloat::kRight) { |
- float_offset = opportunity.size.inline_size - fragment.InlineSize(); |
- exclusion_type = NGExclusion::kFloatRight; |
- } |
- |
- // Add the float as an exclusion. |
- const NGExclusion exclusion = CreateExclusion( |
- fragment, opportunity, float_offset, margins, exclusion_type); |
- constraint_space_->AddExclusion(exclusion); |
- |
- return CalculateLogicalOffsetForOpportunity(opportunity, float_offset, |
- margins); |
-} |
- |
-void NGBlockLayoutAlgorithm::UpdateMarginStrut( |
- const NGDeprecatedMarginStrut& from) { |
- if (!is_fragment_margin_strut_block_start_updated_) { |
- builder_->SetMarginStrutBlockStart(from); |
- is_fragment_margin_strut_block_start_updated_ = true; |
- } |
- builder_->SetMarginStrutBlockEnd(from); |
-} |
- |
NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins( |
const NGConstraintSpace& space, |
const ComputedStyle& style) { |
@@ -635,10 +670,9 @@ NGBlockLayoutAlgorithm::CreateConstraintSpaceForCurrentChild() { |
bool shrink_to_fit = CurrentChildStyle().display() == EDisplay::InlineBlock || |
CurrentChildStyle().isFloating(); |
DCHECK(current_child_); |
- space_builder_ |
- ->SetIsNewFormattingContext( |
- IsNewFormattingContextForInFlowBlockLevelChild(ConstraintSpace(), |
- CurrentChildStyle())) |
+ bool is_new_bfc = IsNewFormattingContextForInFlowBlockLevelChild( |
+ ConstraintSpace(), CurrentChildStyle()); |
+ space_builder_->SetIsNewFormattingContext(is_new_bfc) |
.SetIsShrinkToFit(shrink_to_fit) |
.SetWritingMode( |
FromPlatformWritingMode(CurrentChildStyle().getWritingMode())) |
@@ -649,11 +683,42 @@ NGBlockLayoutAlgorithm::CreateConstraintSpaceForCurrentChild() { |
curr_child_margins_ = CalculateMargins(*space_builder_->ToConstraintSpace(), |
CurrentChildStyle()); |
- NGConstraintSpace* child_space = space_builder_->ToConstraintSpace(); |
+ // Clearance : |
+ // - Collapse margins |
+ // - Update curr_bfc_offset and parent BFC offset if needed. |
+ // - Position all pending floats as position is known now. |
+ // TODO(glebl): Fix the use case with clear: left and an intruding right. |
+ // https://software.hixie.ch/utilities/js/live-dom-viewer/saved/4847 |
+ if (CurrentChildStyle().clear() != EClear::kNone) { |
+ curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
+ UpdateFragmentBfcOffset(curr_bfc_offset_, ConstraintSpace(), builder_); |
+ // Only collapse margins if it's an adjoining block with clearance. |
+ if (!content_size_) { |
+ curr_margin_strut_ = NGMarginStrut(); |
+ curr_child_margins_.block_start = LayoutUnit(); |
+ } |
+ PositionPendingFloats(curr_bfc_offset_, builder_); |
+ AdjustToClearance(constraint_space_->Exclusions(), CurrentChildStyle(), |
+ builder_->BfcOffset().value(), &content_size_); |
+ } |
+ |
+ // 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); |
+ space_builder_->SetMarginStrut(curr_margin_strut_); |
+ |
+ // Set estimated BFC offset to the next child's constraint space. |
+ curr_bfc_offset_ = builder_->BfcOffset() ? builder_->BfcOffset().value() |
+ : ConstraintSpace().BfcOffset(); |
+ curr_bfc_offset_.block_offset += content_size_; |
+ curr_bfc_offset_.inline_offset += border_and_padding_.inline_start; |
+ if (ConstraintSpace().IsNewFormattingContext()) { |
+ curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; |
+ } |
+ space_builder_->SetBfcOffset(curr_bfc_offset_); |
- // TODO(layout-ng): Set offset through the space builder. |
- child_space->SetOffset(GetChildSpaceOffset()); |
- return child_space; |
+ return space_builder_->ToConstraintSpace(); |
} |
DEFINE_TRACE(NGBlockLayoutAlgorithm) { |