Commit a7b54126 authored by David Grogan's avatar David Grogan Committed by Commit Bot

[LayoutNG] Make flexboxes stretch their items

Includes moving the stretched size computation from legacy to FlexItem
so that NG can use it.

A big hack is that stretched items don't use the height of their parent
lines, they use the whole container height because we haven't
implemented line size calculation yet. This works for the majority of
cases.

About 6 tests newly fail. Some multi-line flex containers now fail
because of the above hack. But some tests with images that are flex
items fail because NG doesn't copy their data to legacy because there
are unplaced floats internal to the image (something related to alt
text). I haven't looked into why this used to work but fails now.

This patch nets roughly 110 layout test lines removed.

Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_layout_ng
Change-Id: I0083e80797c1f01c8cc4c63ac696d68063f67ff2
Bug: 845235
Reviewed-on: https://chromium-review.googlesource.com/c/1285851Reviewed-by: default avatarChristian Biesinger <cbiesinger@chromium.org>
Commit-Queue: David Grogan <dgrogan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#604457}
parent 70536c5b
......@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/core/layout/flexible_box_algorithm.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
#include "third_party/blink/renderer/core/layout/min_max_size.h"
namespace blink {
......@@ -139,6 +140,28 @@ void FlexItem::UpdateAutoMarginsInMainAxis(LayoutUnit auto_margin_offset) {
}
}
void FlexItem::ComputeStretchedSize(LayoutUnit line_cross_axis_extent) {
// TODO(dgrogan): Pass resolved cross-axis MinMaxSize to FlexItem
// constructor. Then use cross_axis_min_max.ClampSizeToMinAndMax instead of
// relying on legacy in this method.
DCHECK_EQ(Alignment(), ItemPosition::kStretch);
LayoutFlexibleBox* flexbox = ToLayoutFlexibleBox(box->Parent());
if (!HasOrthogonalFlow() && box->StyleRef().LogicalHeight().IsAuto()) {
LayoutUnit stretched_logical_height =
std::max(box->BorderAndPaddingLogicalHeight(),
line_cross_axis_extent - CrossAxisMarginExtent());
cross_axis_size = box->ConstrainLogicalHeightByMinMax(
stretched_logical_height, box->IntrinsicContentLogicalHeight());
} else if (HasOrthogonalFlow() && box->StyleRef().LogicalWidth().IsAuto()) {
LayoutUnit child_width = (line_cross_axis_extent - CrossAxisMarginExtent())
.ClampNegativeToZero();
// This probably doesn't work in NG because flexbox might not yet know its
// CrossAxisContentExtent()
cross_axis_size = box->ConstrainLogicalWidthByMinMax(
child_width, flexbox->CrossAxisContentExtent(), flexbox);
}
}
void FlexLine::FreezeViolations(ViolationsVector& violations) {
for (size_t i = 0; i < violations.size(); ++i) {
DCHECK(!violations[i]->frozen) << i;
......
......@@ -112,6 +112,10 @@ class FlexItem {
void UpdateAutoMarginsInMainAxis(LayoutUnit auto_margin_offset);
// Computes the cross-axis size that a stretched item should have and stores
// it in cross_axis_size. DCHECKs if the item is not stretch aligned.
void ComputeStretchedSize(LayoutUnit line_cross_axis_extent);
FlexLayoutAlgorithm* algorithm;
LayoutBox* box;
const LayoutUnit flex_base_content_size;
......
......@@ -1547,7 +1547,7 @@ void LayoutFlexibleBox::AlignChildren(Vector<FlexLine>& line_contexts) {
ItemPosition position = flex_item.Alignment();
if (position == ItemPosition::kStretch) {
ComputeStretchedSizeForChild(flex_item, line_cross_axis_extent);
flex_item.ComputeStretchedSize(line_cross_axis_extent);
ApplyStretchAlignmentToChild(flex_item);
}
LayoutUnit available_space =
......@@ -1587,29 +1587,6 @@ void LayoutFlexibleBox::AlignChildren(Vector<FlexLine>& line_contexts) {
}
}
void LayoutFlexibleBox::ComputeStretchedSizeForChild(
FlexItem& flex_item,
LayoutUnit line_cross_axis_extent) {
DCHECK_EQ(flex_item.Alignment(), ItemPosition::kStretch);
LayoutBox& child = *flex_item.box;
if (!flex_item.HasOrthogonalFlow() &&
child.StyleRef().LogicalHeight().IsAuto()) {
LayoutUnit stretched_logical_height =
std::max(child.BorderAndPaddingLogicalHeight(),
line_cross_axis_extent - flex_item.CrossAxisMarginExtent());
DCHECK(!child.NeedsLayout());
flex_item.cross_axis_size = child.ConstrainLogicalHeightByMinMax(
stretched_logical_height, child.IntrinsicContentLogicalHeight());
} else if (flex_item.HasOrthogonalFlow() &&
child.StyleRef().LogicalWidth().IsAuto()) {
LayoutUnit child_width =
(line_cross_axis_extent - flex_item.CrossAxisMarginExtent())
.ClampNegativeToZero();
flex_item.cross_axis_size = child.ConstrainLogicalWidthByMinMax(
child_width, CrossAxisContentExtent(), this);
}
}
void LayoutFlexibleBox::ApplyStretchAlignmentToChild(FlexItem& flex_item) {
LayoutBox& child = *flex_item.box;
if (!flex_item.HasOrthogonalFlow() &&
......
......@@ -94,6 +94,7 @@ class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
// Returns true if the position changed. In that case, the child will have to
// be laid out again.
bool SetStaticPositionForPositionedLayout(LayoutBox& child);
LayoutUnit CrossAxisContentExtent() const;
protected:
void ComputeIntrinsicLogicalWidths(
......@@ -121,7 +122,6 @@ class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
LayoutUnit MainAxisContentExtentForChildIncludingScrollbar(
const LayoutBox& child) const;
LayoutUnit CrossAxisExtent() const;
LayoutUnit CrossAxisContentExtent() const;
LayoutUnit MainAxisContentExtent(LayoutUnit content_logical_height);
LayoutUnit ComputeMainAxisExtentForChild(const LayoutBox& child,
SizeType,
......@@ -190,10 +190,6 @@ class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
LayoutUnit available_free_space);
void AlignFlexLines(Vector<FlexLine>&);
void AlignChildren(Vector<FlexLine>&);
// Computes the cross-axis size that a stretched child should have and stores
// it in child.cross_axis_size.
void ComputeStretchedSizeForChild(FlexItem& child,
LayoutUnit line_cross_axis_extent);
void ApplyStretchAlignmentToChild(FlexItem& child);
void FlipForRightToLeftColumn(const Vector<FlexLine>& line_contexts);
void FlipForWrapReverse(const Vector<FlexLine>&,
......
......@@ -7,6 +7,7 @@
#include <memory>
#include "third_party/blink/renderer/core/layout/flexible_box_algorithm.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
......@@ -28,9 +29,10 @@ scoped_refptr<NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
NGLogicalSize flex_container_border_box_size =
CalculateBorderBoxSize(ConstraintSpace(), Node());
NGBoxStrut flex_container_border_scrollbar_padding =
CalculateBorderScrollbarPadding(ConstraintSpace(), Node());
NGLogicalSize flex_container_content_box_size = ShrinkAvailableSize(
flex_container_border_box_size,
CalculateBorderScrollbarPadding(ConstraintSpace(), Node()));
flex_container_border_box_size, flex_container_border_scrollbar_padding);
LayoutUnit flex_container_border_box_inline_size =
flex_container_border_box_size.inline_size;
LayoutUnit flex_container_content_inline_size =
......@@ -101,10 +103,10 @@ scoped_refptr<NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
.ng_input_node = child;
}
NGBoxStrut borders_scrollbar_padding =
CalculateBorderScrollbarPadding(ConstraintSpace(), Node());
LayoutUnit main_axis_offset = borders_scrollbar_padding.inline_start;
LayoutUnit cross_axis_offset = borders_scrollbar_padding.block_start;
LayoutUnit main_axis_offset =
flex_container_border_scrollbar_padding.inline_start;
LayoutUnit cross_axis_offset =
flex_container_border_scrollbar_padding.block_start;
FlexLine* line;
while ((line = algorithm.ComputeNextFlexLine(
flex_container_border_box_inline_size))) {
......@@ -139,21 +141,54 @@ scoped_refptr<NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
// in to the next iteration.
line->ComputeLineItemsPosition(main_axis_offset, cross_axis_offset);
for (wtf_size_t i = 0; i < line->line_items.size(); ++i) {
FlexItem& flex_item = line->line_items[i];
container_builder_.AddChild(
*flex_item.layout_result,
{flex_item.desired_location.X(), flex_item.desired_location.Y()});
}
// TODO(dgrogan): For column flex containers, keep track of tallest flex
// line and pass to ComputeBlockSizeForFragment as content_size.
}
LayoutUnit intrinsic_block_content_size = cross_axis_offset;
LayoutUnit intrinsic_block_size =
intrinsic_block_content_size + borders_scrollbar_padding.BlockSum();
intrinsic_block_content_size +
flex_container_border_scrollbar_padding.BlockSum();
LayoutUnit block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), intrinsic_block_size);
// Apply stretch alignment.
// TODO(dgrogan): Move this to its own method, which means making some of the
// container-specific local variables into data members.
// TODO(dgrogan): Change this to final_content_cross_size when column
// flexboxes are supported.
LayoutUnit final_content_block_size =
block_size - flex_container_border_scrollbar_padding.BlockSum();
for (FlexLine& line_context : algorithm.FlexLines()) {
for (wtf_size_t child_number = 0;
child_number < line_context.line_items.size(); ++child_number) {
FlexItem& flex_item = line_context.line_items[child_number];
if (flex_item.Alignment() == ItemPosition::kStretch) {
flex_item.ComputeStretchedSize(
// TODO(dgrogan): Change this to line_context.cross_axis_extent once
// lines are also sized and spaced.
final_content_block_size);
NGConstraintSpaceBuilder space_builder(ConstraintSpace());
NGLogicalSize available_size(flex_item.flexed_content_size +
flex_item.main_axis_border_and_padding,
flex_item.cross_axis_size);
space_builder.SetAvailableSize(available_size);
space_builder.SetPercentageResolutionSize(
flex_container_content_box_size);
space_builder.SetIsFixedSizeInline(true);
space_builder.SetIsFixedSizeBlock(true);
NGConstraintSpace child_space = space_builder.ToConstraintSpace(
flex_item.box->Style()->GetWritingMode());
flex_item.layout_result =
ToNGBlockNode(flex_item.ng_input_node)
.Layout(child_space, nullptr /*break token*/);
}
container_builder_.AddChild(
*flex_item.layout_result,
{flex_item.desired_location.X(), flex_item.desired_location.Y()});
}
}
container_builder_.SetBlockSize(block_size);
container_builder_.SetInlineSize(flex_container_border_box_inline_size);
container_builder_.SetBorders(ComputeBorders(ConstraintSpace(), Style()));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment