Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(546)

Unified Diff: third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc

Issue 2655783006: Top down version of algorithm to position margins and floats in LayoutNG (Closed)
Patch Set: git rebase-update Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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) {

Powered by Google App Engine
This is Rietveld 408576698