Chromium Code Reviews| 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 bd107013392b4316412488ea3648a0372bcb5893..dc1b8e35dc7f303cd0af59062a5597f1be610743 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 |
| @@ -23,24 +23,32 @@ |
| 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, |
| +// Adjusts content_size to 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; |
| + |
| + // Exclusions(stored in BFC coordinates), content_size can be negative or 0 |
| + // If left or right exclusion are available then convert them to the relative |
| + // offset(exclusion.BlockEnd - from_offset) and compare them with content_size |
| + 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::ClearNone: |
| @@ -59,21 +67,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, |
|
ikilpatrick
2017/01/26 04:37:25
drop reference.
Gleb Lanbin
2017/01/31 00:25:01
Done.
|
| + const NGBoxStrut& margins, |
| NGExclusion::Type exclusion_type) { |
| NGExclusion exclusion; |
| exclusion.type = exclusion_type; |
| @@ -81,16 +80,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 +112,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 +135,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, |
|
ikilpatrick
2017/01/26 04:37:26
drop the reference, this is a single int basically
Gleb Lanbin
2017/01/31 00:25:01
Done.
|
| + 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 +158,58 @@ 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 |
|
ikilpatrick
2017/01/26 04:37:25
.nit space "position ("
Gleb Lanbin
2017/01/31 00:25:01
Done.
|
| +// 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; |
| + NGBoxFragment* float_fragment = |
| + new NGBoxFragment(float_space->WritingMode(), float_space->Direction(), |
| + toNGPhysicalBoxFragment(floating_object->fragment)); |
|
ikilpatrick
2017/01/26 04:37:25
DCHECK(floating_object->fragment) ?
Gleb Lanbin
2017/01/31 00:25:01
Done.
|
| + // 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 PositionFloats(const NGLogicalOffset& origin_point, |
|
ikilpatrick
2017/01/26 04:37:26
is "Pending" floats a better name than unpositione
Gleb Lanbin
2017/01/31 00:25:01
I thought about that. Here is my rationale behind
|
| + 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 +259,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 +290,28 @@ bool NGBlockLayoutAlgorithm::ComputeMinAndMaxContentSizes( |
| return true; |
| } |
| +NGLogicalOffset NGBlockLayoutAlgorithm::PositionFragmentWithKnownBfcOffset( |
| + const NGLogicalOffset& offset) { |
| + curr_bfc_offset_.block_offset = offset.block_offset; |
| + // First block that knows its position. Update the parent's BFC offset. |
| + if (!builder_->BfcOffset()) { |
| + NGLogicalOffset parent_bfc_offset = |
| + ConstraintSpace().IsNewFormattingContext() ? NGLogicalOffset() |
| + : curr_bfc_offset_; |
| + builder_->SetBfcOffset(parent_bfc_offset); |
| + } |
| + |
| + // OK to position pending floats. curr_bfc_offset_ and parent's BFC offset |
| + // are accurate here. |
| + PositionFloats(curr_bfc_offset_, builder_); |
| + |
| + LayoutUnit block_offset = |
| + offset.block_offset - builder_->BfcOffset().value().block_offset; |
| + LayoutUnit inline_offset = |
| + border_and_padding_.inline_start + curr_child_margins_.inline_start; |
| + return {inline_offset, block_offset}; |
| +} |
| + |
| NGPhysicalFragment* NGBlockLayoutAlgorithm::Layout() { |
| WTF::Optional<MinAndMaxContentSizes> sizes; |
| if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style())) { |
| @@ -268,6 +358,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 +369,19 @@ NGPhysicalFragment* NGBlockLayoutAlgorithm::Layout() { |
| current_child_ = first_child_; |
| } |
| + curr_margin_strut_ = constraint_space_->MarginStrut(); |
|
ikilpatrick
2017/01/26 00:49:58
ConstraintSpace() instead?
Gleb Lanbin
2017/01/31 00:25:01
Done.
|
| + curr_bfc_offset_ = ConstraintSpace().BfcOffset(); |
| + |
| + // Margins collapsing: |
| + // Do not collapse margins between parent and its child if there is |
| + // border/padding between them |
|
ikilpatrick
2017/01/26 00:49:58
.nit period.
Gleb Lanbin
2017/01/31 00:25:01
Done.
|
| + if (border_and_padding_.block_start) { |
| + curr_bfc_offset_.block_offset += curr_margin_strut_.Collapse(); |
| + 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 +406,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_.Collapse(); |
| + curr_margin_strut_ = NGMarginStrut(); |
| + } |
| // Recompute the block-axis size now that we know our content size. |
| block_size = |
| @@ -310,6 +424,17 @@ NGPhysicalFragment* NGBlockLayoutAlgorithm::Layout() { |
| LayoutOutOfFlowChildren(); |
| + // Set offset if the size is not empty. |
|
ikilpatrick
2017/01/26 00:49:57
Set our BFC offset if ... ? (up to you)
Gleb Lanbin
2017/01/31 00:25:01
Done.
|
| + if (block_size && !builder_->BfcOffset()) { |
| + curr_bfc_offset_.block_offset += curr_margin_strut_.Collapse(); |
| + builder_->SetBfcOffset(curr_bfc_offset_); |
| + } |
| + |
| + if (!Style().logicalHeight().isAuto()) { |
|
ikilpatrick
2017/01/26 00:49:57
add comment explaining what's going on here.
ikilpatrick
2017/01/26 00:49:58
TODO(glebl): handle minLogicalHeight, maxLogicalHe
Gleb Lanbin
2017/01/31 00:25:01
Done.
Gleb Lanbin
2017/01/31 00:25:01
Done.
|
| + curr_margin_strut_ = NGMarginStrut(); |
| + } |
| + builder_->SetEndMarginStrut(curr_margin_strut_); |
| + |
| builder_->SetInlineOverflow(max_inline_size_).SetBlockOverflow(content_size_); |
| if (ConstraintSpace().HasBlockFragmentation()) |
| @@ -320,23 +445,60 @@ 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); |
| + // 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 as 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_.Collapse(); |
| + PositionFloats(origin_point, builder_); |
| + } |
| + return; |
| } |
| + |
| + // Collapse empty block's margins. |
| + if (!fragment.BlockSize()) { |
| + curr_margin_strut_.Append(curr_child_margins_.block_end); |
| + } |
| + |
| + NGLogicalOffset fragment_offset = { |
| + border_and_padding_.inline_start + curr_child_margins_.inline_start, |
| + content_size_}; |
| + if (fragment.BfcOffset()) |
| + fragment_offset = |
| + PositionFragmentWithKnownBfcOffset(fragment.BfcOffset().value()); |
| + |
| 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()); |
| } |
| void NGBlockLayoutAlgorithm::LayoutOutOfFlowChildren() { |
| @@ -505,133 +667,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) { |
| @@ -660,10 +695,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())) |
| @@ -674,11 +708,41 @@ 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. |
|
ikilpatrick
2017/01/26 04:37:25
maybe a note/todo that we don't think this will wo
Gleb Lanbin
2017/01/31 00:25:01
Done.
|
| + if (CurrentChildStyle().clear()) { |
| + curr_bfc_offset_.block_offset += curr_margin_strut_.Collapse(); |
| + if (!builder_->BfcOffset()) { |
| + builder_->SetBfcOffset(curr_bfc_offset_); |
| + } |
| + // Only collapse margins if it's an adjoining block with clearance. |
| + if (!content_size_) { |
| + curr_margin_strut_ = NGMarginStrut(); |
| + curr_child_margins_.block_start = LayoutUnit(); |
| + } |
| + PositionFloats(curr_bfc_offset_, builder_); |
| + AdjustToClearance(constraint_space_->Exclusions(), CurrentChildStyle(), |
| + builder_->BfcOffset().value(), &content_size_); |
| + } |
| + |
| + // Collapse the current margin strut with child's block start margin. |
|
ikilpatrick
2017/01/26 04:37:25
s/Collapse/Append? or maybe we should rename NGMar
Gleb Lanbin
2017/01/31 00:25:01
Done.
|
| + // non empty border/padding use cases are handled inside of the child's layout |
|
ikilpatrick
2017/01/26 04:37:26
.nit capital N, period.
Gleb Lanbin
2017/01/31 00:25:01
Done.
|
| + 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) { |