diff -up chromium-60.0.3112.90/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc.perchild chromium-60.0.3112.90/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc --- chromium-60.0.3112.90/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc.perchild 2017-08-02 18:05:34.000000000 -0400 +++ chromium-60.0.3112.90/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc 2017-08-09 13:30:01.000000000 -0400 @@ -55,11 +55,11 @@ NGInlineLayoutAlgorithm::NGInlineLayoutA // Only resolve our BFC offset if we know that we are non-empty as we may // need to pass through our margin strut. if (!inline_node->Items().IsEmpty()) { - NGLogicalOffset bfc_offset = ConstraintSpace().BfcOffset(); - bfc_offset.block_offset += ConstraintSpace().MarginStrut().Sum(); - MaybeUpdateFragmentBfcOffset(ConstraintSpace(), bfc_offset, + LayoutUnit bfc_block_offset = ConstraintSpace().BfcOffset().block_offset; + bfc_block_offset += ConstraintSpace().MarginStrut().Sum(); + MaybeUpdateFragmentBfcOffset(ConstraintSpace(), bfc_block_offset, &container_builder_); - PositionPendingFloats(bfc_offset.block_offset, &container_builder_, + PositionPendingFloats(bfc_block_offset, &container_builder_, MutableConstraintSpace()); } @@ -222,6 +222,7 @@ bool NGInlineLayoutAlgorithm::PlaceItems NGLineHeightMetrics line_metrics_with_leading = line_metrics; line_metrics_with_leading.AddLeading(line_style.ComputedLineHeightAsFixed()); NGLineBoxFragmentBuilder line_box(Node()); + line_box.SetWritingMode(ConstraintSpace().WritingMode()); // Compute heights of all inline items by placing the dominant baseline at 0. // The baseline is adjusted after the height of the line box is computed. @@ -231,8 +232,7 @@ bool NGInlineLayoutAlgorithm::PlaceItems // Place items from line-left to line-right along with the baseline. // Items are already bidi-reordered to the visual order. - LayoutUnit line_left_position = LogicalLeftOffset(); - LayoutUnit position = line_left_position; + LayoutUnit position; for (auto& item_result : *line_items) { const NGInlineItem& item = items[item_result.item_index]; @@ -253,13 +253,28 @@ bool NGInlineLayoutAlgorithm::PlaceItems item_result.end_offset); line_box.AddChild(std::move(text_fragment), {position, box->text_top}); } else if (item.Type() == NGInlineItem::kOpenTag) { - box = box_states_.OnOpenTag(item, &line_box, &text_builder); + box = box_states_.OnOpenTag(item, &line_box); // Compute text metrics for all inline boxes since even empty inlines // influence the line height. // https://drafts.csswg.org/css2/visudet.html#line-height box->ComputeTextMetrics(*item.Style(), baseline_type_); + text_builder.SetDirection(box->style->Direction()); + // TODO(kojii): We may need more conditions to create box fragments. + if (item.Style()->HasBoxDecorationBackground()) { + // TODO(kojii): These are once computed in NGLineBreaker. Should copy to + // NGInlineItemResult to reuse here. + NGBoxStrut borders = ComputeBorders(*constraint_space_, *item.Style()); + NGBoxStrut paddings = ComputePadding(*constraint_space_, *item.Style()); + // TODO(kojii): Set paint edges. + box->SetNeedsBoxFragment(position, + borders.block_start + paddings.block_start, + borders.BlockSum() + paddings.BlockSum()); + } } else if (item.Type() == NGInlineItem::kCloseTag) { - box = box_states_.OnCloseTag(item, &line_box, box, baseline_type_); + position += item_result.inline_size; + box = box_states_.OnCloseTag(item, &line_box, box, baseline_type_, + position); + continue; } else if (item.Type() == NGInlineItem::kAtomicInline) { box = PlaceAtomicInline(item, &item_result, position, &line_box, &text_builder); @@ -286,12 +301,11 @@ bool NGInlineLayoutAlgorithm::PlaceItems return true; // The line was empty. } - box_states_.OnEndPlaceItems(&line_box, baseline_type_); + box_states_.OnEndPlaceItems(&line_box, baseline_type_, position); // The baselines are always placed at pixel boundaries. Not doing so results // in incorrect layout of text decorations, most notably underlines. - LayoutUnit baseline = content_size_ + line_box.Metrics().ascent + - border_and_padding_.block_start; + LayoutUnit baseline = content_size_ + line_box.Metrics().ascent; baseline = LayoutUnit(baseline.Round()); // Check if the line fits into the constraint space in block direction. @@ -313,19 +327,14 @@ bool NGInlineLayoutAlgorithm::PlaceItems // the line box to the line top. line_box.MoveChildrenInBlockDirection(baseline); - DCHECK_EQ(line_left_position, LogicalLeftOffset()); - LayoutUnit inline_size = position - line_left_position; - line_box.SetInlineSize(inline_size); - - // Account for text align property. - if (Node()->Style().GetTextAlign() == ETextAlign::kRight) { - line_box.MoveChildrenInInlineDirection( - current_opportunity_.size.inline_size - inline_size); - } + LayoutUnit inline_size = position; + NGLogicalOffset offset(LogicalLeftOffset(), + baseline - box_states_.LineBoxState().metrics.ascent); + ApplyTextAlign(&offset.inline_offset, inline_size, + current_opportunity_.size.inline_size); - container_builder_.AddChild( - line_box.ToLineBoxFragment(), - {LayoutUnit(), baseline - box_states_.LineBoxState().metrics.ascent}); + line_box.SetInlineSize(inline_size); + container_builder_.AddChild(line_box.ToLineBoxFragment(), offset); max_inline_size_ = std::max(max_inline_size_, inline_size); content_size_ = line_bottom; @@ -342,7 +351,7 @@ NGInlineBoxState* NGInlineLayoutAlgorith NGTextFragmentBuilder* text_builder) { DCHECK(item_result->layout_result); - NGInlineBoxState* box = box_states_.OnOpenTag(item, line_box, text_builder); + NGInlineBoxState* box = box_states_.OnOpenTag(item, line_box); // For replaced elements, inline-block elements, and inline-table elements, // the height is the height of their margin box. @@ -371,6 +380,7 @@ NGInlineBoxState* NGInlineLayoutAlgorith // TODO(kojii): Try to eliminate the wrapping text fragment and use the // |fragment| directly. Currently |CopyFragmentDataToLayoutBlockFlow| // requires a text fragment. + text_builder->SetDirection(item.Style()->Direction()); text_builder->SetSize({fragment.InlineSize(), block_size}); LayoutUnit line_top = item_result->margins.block_start - metrics.ascent; RefPtr text_fragment = text_builder->ToTextFragment( @@ -378,7 +388,31 @@ NGInlineBoxState* NGInlineLayoutAlgorith item_result->end_offset); line_box->AddChild(std::move(text_fragment), {position, line_top}); - return box_states_.OnCloseTag(item, line_box, box, baseline_type_); + return box_states_.OnCloseTag(item, line_box, box, baseline_type_, + LayoutUnit(0)); +} + +void NGInlineLayoutAlgorithm::ApplyTextAlign(LayoutUnit* line_left, + LayoutUnit inline_size, + LayoutUnit available_width) { + // TODO(kojii): Implement text-align-last. + ETextAlign text_align = LineStyle().GetTextAlign(); + switch (text_align) { + case ETextAlign::kRight: + case ETextAlign::kWebkitRight: + // Wide lines spill out of the block based off direction. + // So even if text-align is right, if direction is LTR, wide lines should + // overflow out of the right side of the block. + // TODO(kojii): Investigate how to handle trailing spaces. + if (inline_size < available_width || + !LineStyle().IsLeftToRightDirection()) + *line_left += available_width - inline_size; + break; + default: + // TODO(layout-dev): Implement. + // Refer to LayoutBlockFlow::UpdateLogicalWidthForAlignment(). + break; + } } void NGInlineLayoutAlgorithm::FindNextLayoutOpportunity() { @@ -396,6 +430,10 @@ void NGInlineLayoutAlgorithm::FindNextLa } RefPtr NGInlineLayoutAlgorithm::Layout() { + // If we are resuming from a break token our start border and padding is + // within a previous fragment. + content_size_ = BreakToken() ? LayoutUnit() : border_and_padding_.block_start; + NGLineBreaker line_breaker(Node(), constraint_space_, BreakToken()); NGInlineItemResults item_results; while (true) { @@ -407,7 +445,7 @@ RefPtr NGInlineLayoutAlg } // TODO(crbug.com/716930): Avoid calculating border/padding twice. - if (!Node()->Items().IsEmpty()) + if (!BreakToken()) content_size_ -= border_and_padding_.block_start; // TODO(kojii): Check if the line box width should be content or available. diff -up chromium-60.0.3112.90/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc.perchild chromium-60.0.3112.90/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc --- chromium-60.0.3112.90/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc.perchild 2017-08-02 18:05:34.000000000 -0400 +++ chromium-60.0.3112.90/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc 2017-08-09 13:30:01.000000000 -0400 @@ -67,14 +67,31 @@ bool IsOutOfSpace(const NGConstraintSpac } // namespace +// This struct is used for communicating to a child the position of the +// previous inflow child. +struct NGPreviousInflowPosition { + LayoutUnit bfc_block_offset; + LayoutUnit logical_block_offset; + NGMarginStrut margin_strut; +}; + +// This strut holds information for the current inflow child. The data is not +// useful outside of handling this single inflow child. +struct NGInflowChildData { + NGLogicalOffset bfc_offset_estimate; + NGMarginStrut margin_strut; + NGBoxStrut margins; +}; + void MaybeUpdateFragmentBfcOffset(const NGConstraintSpace& space, - const NGLogicalOffset& offset, + LayoutUnit bfc_block_offset, NGFragmentBuilder* builder) { DCHECK(builder); if (!builder->BfcOffset()) { - NGLogicalOffset mutable_offset(offset); - AdjustToClearance(space.ClearanceOffset(), &mutable_offset); - builder->SetBfcOffset(mutable_offset); + NGLogicalOffset bfc_offset = {space.BfcOffset().inline_offset, + bfc_block_offset}; + AdjustToClearance(space.ClearanceOffset(), &bfc_offset); + builder->SetBfcOffset(bfc_offset); } } @@ -150,11 +167,13 @@ Optional NGBlockLayou } NGLogicalOffset NGBlockLayoutAlgorithm::CalculateLogicalOffset( + const NGBoxStrut& child_margins, const WTF::Optional& known_fragment_offset) { if (known_fragment_offset) return known_fragment_offset.value() - ContainerBfcOffset(); LayoutUnit inline_offset = - border_and_padding_.inline_start + curr_child_margins_.inline_start; + border_and_padding_.inline_start + child_margins.inline_start; + // TODO(ikilpatrick): Using the content_size_ here looks suspicious - check. return {inline_offset, content_size_}; } @@ -199,17 +218,20 @@ RefPtr NGBlockLayoutAlgo // within a previous fragment. content_size_ = BreakToken() ? LayoutUnit() : border_and_padding_.block_start; - curr_margin_strut_ = ConstraintSpace().MarginStrut(); - curr_bfc_offset_ = ConstraintSpace().BfcOffset(); + NGMarginStrut input_margin_strut = ConstraintSpace().MarginStrut(); + LayoutUnit input_bfc_block_offset = + ConstraintSpace().BfcOffset().block_offset; // 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(); - MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, + input_bfc_block_offset += input_margin_strut.Sum(); + MaybeUpdateFragmentBfcOffset(ConstraintSpace(), input_bfc_block_offset, &container_builder_); - curr_margin_strut_ = NGMarginStrut(); + // We reset the block offset here as it may have been effected by clearance. + input_bfc_block_offset = ContainerBfcOffset().block_offset; + input_margin_strut = NGMarginStrut(); } // If a new formatting context hits the margin collapsing if-branch above @@ -218,29 +240,34 @@ RefPtr NGBlockLayoutAlgo // If we are resuming layout from a break token the same rule applies. Margin // struts cannot pass through break tokens. if (ConstraintSpace().IsNewFormattingContext() || BreakToken()) { - MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, + MaybeUpdateFragmentBfcOffset(ConstraintSpace(), input_bfc_block_offset, &container_builder_); - DCHECK_EQ(curr_margin_strut_, NGMarginStrut()); + DCHECK_EQ(input_margin_strut, NGMarginStrut()); DCHECK_EQ(container_builder_.BfcOffset().value(), NGLogicalOffset()); - curr_bfc_offset_ = {}; } - curr_bfc_offset_.block_offset += content_size_; + input_bfc_block_offset += content_size_; + + NGPreviousInflowPosition previous_inflow_position = { + input_bfc_block_offset, content_size_, input_margin_strut}; while (child) { if (child->IsOutOfFlowPositioned()) { DCHECK(!child_break_token); - HandleOutOfFlowPositioned(ToNGBlockNode(child)); + HandleOutOfFlowPositioned(previous_inflow_position, ToNGBlockNode(child)); } else if (child->IsFloating()) { - HandleFloating(ToNGBlockNode(child), + HandleFloating(previous_inflow_position, ToNGBlockNode(child), ToNGBlockBreakToken(child_break_token)); } else { - NGLogicalOffset child_bfc_offset = PrepareChildLayout(child); + NGInflowChildData child_data = + PrepareChildLayout(previous_inflow_position, child); RefPtr child_space = - CreateConstraintSpaceForChild(child_bfc_offset, *child); + CreateConstraintSpaceForChild(*child, child_data); RefPtr layout_result = child->Layout(child_space.Get(), child_break_token); - FinishChildLayout(*child_space, child, layout_result.Get()); + previous_inflow_position = + FinishChildLayout(*child_space, previous_inflow_position, child_data, + child, layout_result.Get()); } entry = child_iterator.NextChild(); @@ -251,6 +278,9 @@ RefPtr NGBlockLayoutAlgo break; } + NGMarginStrut end_margin_strut = previous_inflow_position.margin_strut; + LayoutUnit end_bfc_block_offset = previous_inflow_position.bfc_block_offset; + // Margins collapsing: // Bottom margins of an in-flow block box doesn't collapse with its last // in-flow block-level child's bottom margin if the box has bottom @@ -258,8 +288,8 @@ RefPtr NGBlockLayoutAlgo 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(); + content_size_ += end_margin_strut.Sum(); + end_margin_strut = NGMarginStrut(); } // Recompute the block-axis size now that we know our content size. @@ -273,10 +303,10 @@ RefPtr NGBlockLayoutAlgo // Non-empty blocks always know their position in space. // TODO(ikilpatrick): This check for a break token seems error prone. if (size.block_size || BreakToken()) { - curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); - MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, + end_bfc_block_offset += end_margin_strut.Sum(); + MaybeUpdateFragmentBfcOffset(ConstraintSpace(), end_bfc_block_offset, &container_builder_); - PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_, + PositionPendingFloats(end_bfc_block_offset, &container_builder_, MutableConstraintSpace()); } @@ -285,9 +315,9 @@ RefPtr NGBlockLayoutAlgo // of its parent if the parent has height != auto() if (!Style().LogicalHeight().IsAuto()) { // TODO(glebl): handle minLogicalHeight, maxLogicalHeight. - curr_margin_strut_ = NGMarginStrut(); + end_margin_strut = NGMarginStrut(); } - container_builder_.SetEndMarginStrut(curr_margin_strut_); + container_builder_.SetEndMarginStrut(end_margin_strut); container_builder_.SetOverflowSize( NGLogicalSize(max_inline_size_, content_size_)); @@ -302,33 +332,32 @@ RefPtr NGBlockLayoutAlgo return container_builder_.ToBoxFragment(); } -void NGBlockLayoutAlgorithm::HandleOutOfFlowPositioned(NGBlockNode* child) { - NGLogicalOffset offset = {border_and_padding_.inline_start, content_size_}; +void NGBlockLayoutAlgorithm::HandleOutOfFlowPositioned( + const NGPreviousInflowPosition& previous_inflow_position, + NGBlockNode* child) { + NGLogicalOffset offset = {border_and_padding_.inline_start, + previous_inflow_position.logical_block_offset}; // We only include the margin strut in the OOF static-position if we know we // aren't going to be a zero-block-size fragment. if (container_builder_.BfcOffset()) - offset.block_offset += curr_margin_strut_.Sum(); + offset.block_offset += previous_inflow_position.margin_strut.Sum(); container_builder_.AddOutOfFlowChildCandidate(child, offset); } -void NGBlockLayoutAlgorithm::HandleFloating(NGBlockNode* child, - NGBlockBreakToken* token) { - // TODO(ikilpatrick): Pass in BFC offset from previous in-flow child. - curr_bfc_offset_ = container_builder_.BfcOffset() - ? container_builder_.BfcOffset().value() - : ConstraintSpace().BfcOffset(); - curr_bfc_offset_.block_offset += content_size_; - +void NGBlockLayoutAlgorithm::HandleFloating( + const NGPreviousInflowPosition& previous_inflow_position, + NGBlockNode* child, + NGBlockBreakToken* token) { // Calculate margins in the BFC's writing mode. - curr_child_margins_ = CalculateMargins(child); + NGBoxStrut margins = CalculateMargins(child); NGLogicalOffset origin_offset = constraint_space_->BfcOffset(); origin_offset.inline_offset += border_and_padding_.inline_start; RefPtr unpositioned_float = NGUnpositionedFloat::Create( child_available_size_, child_percentage_size_, origin_offset, - constraint_space_->BfcOffset(), curr_child_margins_, child, token); + constraint_space_->BfcOffset(), margins, child, token); container_builder_.AddUnpositionedFloat(unpositioned_float); // If there is a break token for a float we must be resuming layout, we must @@ -337,29 +366,28 @@ void NGBlockLayoutAlgorithm::HandleFloat // No need to postpone the positioning if we know the correct offset. if (container_builder_.BfcOffset()) { - NGLogicalOffset origin_point = curr_bfc_offset_; // Adjust origin point to the margins of the last child. // Example:
//
- origin_point.block_offset += curr_margin_strut_.Sum(); - PositionPendingFloats(origin_point.block_offset, &container_builder_, + LayoutUnit origin_block_offset = + previous_inflow_position.bfc_block_offset + + previous_inflow_position.margin_strut.Sum(); + PositionPendingFloats(origin_block_offset, &container_builder_, MutableConstraintSpace()); } } -NGLogicalOffset NGBlockLayoutAlgorithm::PrepareChildLayout( +NGInflowChildData NGBlockLayoutAlgorithm::PrepareChildLayout( + const NGPreviousInflowPosition& previous_inflow_position, NGLayoutInputNode* child) { DCHECK(child); DCHECK(!child->IsFloating()); - // TODO(ikilpatrick): Pass in BFC offset from previous in-flow child. - curr_bfc_offset_ = container_builder_.BfcOffset() - ? container_builder_.BfcOffset().value() - : ConstraintSpace().BfcOffset(); - curr_bfc_offset_.block_offset += content_size_; + LayoutUnit bfc_block_offset = previous_inflow_position.bfc_block_offset; // Calculate margins in parent's writing mode. - curr_child_margins_ = CalculateMargins(child); + NGBoxStrut margins = CalculateMargins(child); + NGMarginStrut margin_strut = previous_inflow_position.margin_strut; bool should_position_pending_floats = !IsNewFormattingContextForBlockLevelChild(Style(), *child) && @@ -371,45 +399,50 @@ NGLogicalOffset NGBlockLayoutAlgorithm:: // be positioned before layout. This also resolves the fragment's bfc offset. if (should_position_pending_floats) { LayoutUnit origin_point_block_offset = - curr_bfc_offset_.block_offset + curr_margin_strut_.Sum(); - MaybeUpdateFragmentBfcOffset( - ConstraintSpace(), - {curr_bfc_offset_.inline_offset, origin_point_block_offset}, - &container_builder_); + bfc_block_offset + margin_strut.Sum(); + MaybeUpdateFragmentBfcOffset(ConstraintSpace(), origin_point_block_offset, + &container_builder_); + // TODO(ikilpatrick): Check if origin_point_block_offset is correct - + // MaybeUpdateFragmentBfcOffset might have changed it due to clearance. PositionPendingFloats(origin_point_block_offset, &container_builder_, MutableConstraintSpace()); } - NGLogicalOffset child_bfc_offset = curr_bfc_offset_; - child_bfc_offset.inline_offset += - {border_and_padding_.inline_start + curr_child_margins_.inline_start}; + NGLogicalOffset child_bfc_offset = { + ConstraintSpace().BfcOffset().inline_offset + + border_and_padding_.inline_start + margins.inline_start, + bfc_block_offset}; + + bool is_new_fc = IsNewFormattingContextForBlockLevelChild(Style(), *child); // Append the current margin strut with child's block start margin. // Non empty border/padding, and new FC use cases are handled inside of the // child's layout. - if (!IsNewFormattingContextForBlockLevelChild(Style(), *child)) - curr_margin_strut_.Append(curr_child_margins_.block_start); + if (!is_new_fc) + margin_strut.Append(margins.block_start); // TODO(crbug.com/716930): We should also collapse margins below once we // remove LayoutInline splitting. // Should collapse margins if our child is a legacy block. - if (IsLegacyBlock(*child)) { - curr_bfc_offset_ += - {border_and_padding_.inline_start + curr_child_margins_.inline_start, - curr_margin_strut_.Sum()}; - MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, - &container_builder_); - PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_, + // TODO(ikilpatrick): I think this can be removed. + if (IsLegacyBlock(*child) && !is_new_fc) { + child_bfc_offset.block_offset += margin_strut.Sum(); + MaybeUpdateFragmentBfcOffset( + ConstraintSpace(), child_bfc_offset.block_offset, &container_builder_); + // TODO(ikilpatrick): Check if child_bfc_offset.block_offset is correct - + // MaybeUpdateFragmentBfcOffset might have changed it due to clearance. + PositionPendingFloats(child_bfc_offset.block_offset, &container_builder_, MutableConstraintSpace()); - curr_margin_strut_ = {}; + margin_strut = {}; } - child_bfc_offset.block_offset = curr_bfc_offset_.block_offset; - return child_bfc_offset; + return {child_bfc_offset, margin_strut, margins}; } -void NGBlockLayoutAlgorithm::FinishChildLayout( +NGPreviousInflowPosition NGBlockLayoutAlgorithm::FinishChildLayout( const NGConstraintSpace& child_space, + const NGPreviousInflowPosition& previous_inflow_position, + const NGInflowChildData& child_data, const NGLayoutInputNode* child, NGLayoutResult* layout_result) { // Pull out unpositioned floats to the current fragment. This may needed if @@ -425,97 +458,134 @@ void NGBlockLayoutAlgorithm::FinishChild // Determine the fragment's position in the parent space. WTF::Optional child_bfc_offset; if (child_space.IsNewFormattingContext()) - child_bfc_offset = PositionNewFc(fragment, child_space); + child_bfc_offset = PositionNewFc(*child, previous_inflow_position, fragment, + child_data, child_space); else if (fragment.BfcOffset()) child_bfc_offset = PositionWithBfcOffset(fragment); else if (IsLegacyBlock(*child)) - child_bfc_offset = PositionLegacy(child_space); + child_bfc_offset = PositionLegacy(child_space, child_data); else if (container_builder_.BfcOffset()) - child_bfc_offset = PositionWithParentBfc(child_space, fragment); + child_bfc_offset = PositionWithParentBfc(child_space, child_data, fragment); - NGLogicalOffset logical_offset = CalculateLogicalOffset(child_bfc_offset); + NGLogicalOffset logical_offset = + CalculateLogicalOffset(child_data.margins, child_bfc_offset); - // Update margin strut. - curr_margin_strut_ = fragment.EndMarginStrut(); - curr_margin_strut_.Append(curr_child_margins_.block_end); + NGMarginStrut margin_strut = fragment.EndMarginStrut(); + margin_strut.Append(child_data.margins.block_end); - // Only modify content_size if BlockSize is not empty. It's needed to prevent - // the situation when logical_offset is included in content_size for empty - // blocks. Example: + // Only modify content_size_ if the fragment's BlockSize is not empty. This is + // needed to prevent the situation when logical_offset is included in + // content_size_ for empty blocks. Example: //
//
//
//
if (fragment.BlockSize()) - content_size_ = fragment.BlockSize() + logical_offset.block_offset; - max_inline_size_ = - std::max(max_inline_size_, fragment.InlineSize() + - curr_child_margins_.InlineSum() + - border_and_padding_.InlineSum()); + content_size_ = std::max( + content_size_, logical_offset.block_offset + fragment.BlockSize()); + max_inline_size_ = std::max( + max_inline_size_, fragment.InlineSize() + child_data.margins.InlineSum() + + border_and_padding_.InlineSum()); container_builder_.AddChild(layout_result, logical_offset); + + // Determine the child's end BFC block offset for the next child to use. + LayoutUnit child_end_bfc_block_offset; + if (child_bfc_offset) { + // TODO(crbug.com/716930): I think the fragment.BfcOffset() condition here + // can be removed once we've removed inline splitting. + if (fragment.BlockSize() || fragment.BfcOffset()) { + child_end_bfc_block_offset = + child_bfc_offset.value().block_offset + fragment.BlockSize(); + } else { + DCHECK_EQ(LayoutUnit(), fragment.BlockSize()); + child_end_bfc_block_offset = previous_inflow_position.bfc_block_offset; + } + } else { + child_end_bfc_block_offset = ConstraintSpace().BfcOffset().block_offset; + } + + return {child_end_bfc_block_offset, + logical_offset.block_offset + fragment.BlockSize(), margin_strut}; } NGLogicalOffset NGBlockLayoutAlgorithm::PositionNewFc( + const NGLayoutInputNode& child, + const NGPreviousInflowPosition& previous_inflow_position, const NGBoxFragment& fragment, + const NGInflowChildData& child_data, const NGConstraintSpace& child_space) { + const ComputedStyle& child_style = child.Style(); + + LayoutUnit child_bfc_offset_estimate = + child_data.bfc_offset_estimate.block_offset; + // 1. Position all pending floats to a temporary space. RefPtr tmp_space = NGConstraintSpaceBuilder(&child_space) .SetIsNewFormattingContext(false) .ToConstraintSpace(child_space.WritingMode()); - PositionFloats(curr_bfc_offset_.block_offset, curr_bfc_offset_.block_offset, - curr_bfc_offset_.block_offset, + PositionFloats(child_bfc_offset_estimate, child_bfc_offset_estimate, + child_bfc_offset_estimate, container_builder_.UnpositionedFloats(), tmp_space.Get()); - NGLogicalOffset origin_offset = curr_bfc_offset_; - origin_offset.inline_offset += border_and_padding_.inline_start; + NGLogicalOffset origin_offset = {ConstraintSpace().BfcOffset().inline_offset + + border_and_padding_.inline_start, + child_bfc_offset_estimate}; + AdjustToClearance( + GetClearanceOffset(ConstraintSpace().Exclusions(), child_style.Clear()), + &origin_offset); // 2. Find an estimated layout opportunity for our fragment. NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment( tmp_space->Exclusions().get(), child_space.AvailableSize(), origin_offset, - curr_child_margins_, fragment.Size()); + child_data.margins, fragment.Size()); + + NGMarginStrut margin_strut = previous_inflow_position.margin_strut; // 3. If the found opportunity lies on the same line with our estimated // child's BFC offset then merge fragment's margins with the current // MarginStrut. - if (opportunity.offset.block_offset == curr_bfc_offset_.block_offset) - curr_margin_strut_.Append(curr_child_margins_.block_start); - curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); - curr_margin_strut_ = {}; + if (opportunity.offset.block_offset == child_bfc_offset_estimate) + margin_strut.Append(child_data.margins.block_start); + child_bfc_offset_estimate += margin_strut.Sum(); // 4. The child's BFC block offset is known here. - MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, + MaybeUpdateFragmentBfcOffset(ConstraintSpace(), child_bfc_offset_estimate, &container_builder_); - PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_, + PositionPendingFloats(child_bfc_offset_estimate, &container_builder_, MutableConstraintSpace()); - origin_offset = curr_bfc_offset_; - origin_offset.inline_offset += border_and_padding_.inline_start; + origin_offset = {ConstraintSpace().BfcOffset().inline_offset + + border_and_padding_.inline_start, + child_bfc_offset_estimate}; + AdjustToClearance( + GetClearanceOffset(ConstraintSpace().Exclusions(), child_style.Clear()), + &origin_offset); // 5. Find the final layout opportunity for the fragment after all pending // floats are positioned at the correct BFC block's offset. opportunity = FindLayoutOpportunityForFragment( MutableConstraintSpace()->Exclusions().get(), child_space.AvailableSize(), - origin_offset, curr_child_margins_, fragment.Size()); + origin_offset, child_data.margins, fragment.Size()); - curr_bfc_offset_ = opportunity.offset; - return curr_bfc_offset_; + return opportunity.offset; } NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithBfcOffset( const NGBoxFragment& fragment) { DCHECK(fragment.BfcOffset()); - curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset; - MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, + LayoutUnit bfc_block_offset = fragment.BfcOffset().value().block_offset; + MaybeUpdateFragmentBfcOffset(ConstraintSpace(), bfc_block_offset, &container_builder_); - PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_, + PositionPendingFloats(bfc_block_offset, &container_builder_, MutableConstraintSpace()); return fragment.BfcOffset().value(); } NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithParentBfc( const NGConstraintSpace& space, + const NGInflowChildData& child_data, const NGBoxFragment& fragment) { // The child must be an in-flow zero-block-size fragment, use its end margin // strut for positioning. @@ -523,22 +593,28 @@ NGLogicalOffset NGBlockLayoutAlgorithm:: DCHECK_EQ(fragment.BlockSize(), LayoutUnit()); NGMarginStrut margin_strut = fragment.EndMarginStrut(); - margin_strut.Append(curr_child_margins_.block_end); + margin_strut.Append(child_data.margins.block_end); - curr_bfc_offset_ += - {border_and_padding_.inline_start + curr_child_margins_.inline_start, - margin_strut.Sum()}; - AdjustToClearance(space.ClearanceOffset(), &curr_bfc_offset_); - PositionPendingFloatsFromOffset( - curr_bfc_offset_.block_offset, curr_bfc_offset_.block_offset, - &container_builder_, MutableConstraintSpace()); - return curr_bfc_offset_; + NGLogicalOffset bfc_offset = { + ConstraintSpace().BfcOffset().inline_offset + + border_and_padding_.inline_start + child_data.margins.inline_start, + child_data.bfc_offset_estimate.block_offset + margin_strut.Sum()}; + AdjustToClearance(space.ClearanceOffset(), &bfc_offset); + PositionPendingFloatsFromOffset(bfc_offset.block_offset, + bfc_offset.block_offset, &container_builder_, + MutableConstraintSpace()); + return bfc_offset; } NGLogicalOffset NGBlockLayoutAlgorithm::PositionLegacy( - const NGConstraintSpace& child_space) { - AdjustToClearance(child_space.ClearanceOffset(), &curr_bfc_offset_); - return curr_bfc_offset_; + const NGConstraintSpace& child_space, + const NGInflowChildData& child_data) { + NGLogicalOffset bfc_offset = {ConstraintSpace().BfcOffset().inline_offset + + border_and_padding_.inline_start + + child_data.margins.inline_start, + child_data.bfc_offset_estimate.block_offset}; + AdjustToClearance(child_space.ClearanceOffset(), &bfc_offset); + return bfc_offset; } void NGBlockLayoutAlgorithm::FinalizeForFragmentation() { @@ -609,8 +685,8 @@ NGBoxStrut NGBlockLayoutAlgorithm::Calcu } RefPtr NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild( - const NGLogicalOffset& child_bfc_offset, - const NGLayoutInputNode& child) { + const NGLayoutInputNode& child, + const NGInflowChildData& child_data) { NGConstraintSpaceBuilder space_builder(MutableConstraintSpace()); space_builder.SetAvailableSize(child_available_size_) .SetPercentageResolutionSize(child_percentage_size_); @@ -618,8 +694,8 @@ RefPtr NGBlockLayoutA const ComputedStyle& child_style = child.Style(); bool is_new_bfc = IsNewFormattingContextForBlockLevelChild(Style(), child); space_builder.SetIsNewFormattingContext(is_new_bfc) - .SetBfcOffset(child_bfc_offset) - .SetMarginStrut(curr_margin_strut_); + .SetBfcOffset(child_data.bfc_offset_estimate) + .SetMarginStrut(child_data.margin_strut); if (!is_new_bfc) { space_builder.SetUnpositionedFloats( @@ -646,7 +722,7 @@ RefPtr NGBlockLayoutA // position in the formatting context, and are able to adjust the // fragmentation line. if (is_new_bfc) { - space_available -= child_bfc_offset.block_offset; + space_available -= child_data.bfc_offset_estimate.block_offset; } } space_builder.SetFragmentainerSpaceAvailable(space_available); diff -up chromium-60.0.3112.90/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h.perchild chromium-60.0.3112.90/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h --- chromium-60.0.3112.90/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h.perchild 2017-08-02 18:05:34.000000000 -0400 +++ chromium-60.0.3112.90/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h 2017-08-09 13:30:01.000000000 -0400 @@ -18,10 +18,12 @@ namespace blink { class NGConstraintSpace; class NGLayoutResult; +struct NGInflowChildData; +struct NGPreviousInflowPosition; // Updates the fragment's BFC offset if it's not already set. void MaybeUpdateFragmentBfcOffset(const NGConstraintSpace&, - const NGLogicalOffset&, + LayoutUnit bfc_block_offset, NGFragmentBuilder* builder); // Positions pending floats starting from {@origin_block_offset} and relative @@ -52,15 +54,19 @@ class CORE_EXPORT NGBlockLayoutAlgorithm // Creates a new constraint space for the current child. RefPtr CreateConstraintSpaceForChild( - const NGLogicalOffset& child_bfc_offset, - const NGLayoutInputNode&); + const NGLayoutInputNode& child, + const NGInflowChildData& child_data); // @return Estimated BFC offset for the "to be layout" child. - NGLogicalOffset PrepareChildLayout(NGLayoutInputNode*); + NGInflowChildData PrepareChildLayout(const NGPreviousInflowPosition&, + NGLayoutInputNode*); - void FinishChildLayout(const NGConstraintSpace&, - const NGLayoutInputNode* child, - NGLayoutResult*); + NGPreviousInflowPosition FinishChildLayout( + const NGConstraintSpace&, + const NGPreviousInflowPosition& prev_data, + const NGInflowChildData& child_data, + const NGLayoutInputNode* child, + NGLayoutResult*); // Positions the fragment that establishes a new formatting context. // @@ -81,7 +87,10 @@ class CORE_EXPORT NGBlockLayoutAlgorithm // then it will be placed there and we collapse its margin. // 2) If #new-fc is too big then we need to clear its position and place it // below #float ignoring its vertical margin. - NGLogicalOffset PositionNewFc(const NGBoxFragment&, + NGLogicalOffset PositionNewFc(const NGLayoutInputNode& child, + const NGPreviousInflowPosition&, + const NGBoxFragment&, + const NGInflowChildData& child_data, const NGConstraintSpace& child_space); // Positions the fragment that knows its BFC offset. @@ -95,12 +104,16 @@ class CORE_EXPORT NGBlockLayoutAlgorithm //
//
NGLogicalOffset PositionWithParentBfc(const NGConstraintSpace&, + const NGInflowChildData& child_data, const NGBoxFragment&); - NGLogicalOffset PositionLegacy(const NGConstraintSpace& child_space); + NGLogicalOffset PositionLegacy(const NGConstraintSpace& child_space, + const NGInflowChildData& child_data); - void HandleOutOfFlowPositioned(NGBlockNode*); - void HandleFloating(NGBlockNode*, NGBlockBreakToken*); + void HandleOutOfFlowPositioned(const NGPreviousInflowPosition&, NGBlockNode*); + void HandleFloating(const NGPreviousInflowPosition&, + NGBlockNode*, + NGBlockBreakToken*); // Final adjustments before fragment creation. We need to prevent the // fragment from crossing fragmentainer boundaries, and rather create a break @@ -112,6 +125,7 @@ class CORE_EXPORT NGBlockLayoutAlgorithm // or {@code known_fragment_offset} if the fragment knows it's offset // @return Fragment's offset relative to the fragment's parent. NGLogicalOffset CalculateLogicalOffset( + const NGBoxStrut& child_margins, const WTF::Optional& known_fragment_offset); NGLogicalSize child_available_size_; @@ -120,10 +134,6 @@ class CORE_EXPORT NGBlockLayoutAlgorithm NGBoxStrut border_and_padding_; LayoutUnit content_size_; LayoutUnit max_inline_size_; - // MarginStrut for the previous child. - NGMarginStrut curr_margin_strut_; - NGLogicalOffset curr_bfc_offset_; - NGBoxStrut curr_child_margins_; }; } // namespace blink