| 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) {
|
|
|