Commit 63a7311c authored by David Grogan's avatar David Grogan Committed by Commit Bot

[LayoutNG] Basic flexbox logic behind runtime flag

This doesn't produce anything good yet. It's a basic implementation that
interacts with FlexLayoutAlgorithm for a very narrow range of flex
items and stuffs the results into NGLayoutResult.

There's no attempt at painting or copying results back to legacy.

Abusing LayoutNGBlockFlow in LayoutObject.cpp will have to be fixed
soon. This will be the first layout type that doesn't inherit from
LayoutBlockFlow, but in this patch it still uses LayoutNGBlockFlow.

Cq-Include-Trybots: master.tryserver.chromium.linux:linux_layout_tests_layout_ng
Change-Id: I82195d5c561ba8ff67b00894b17ad72f14a52535
Reviewed-on: https://chromium-review.googlesource.com/961793
Commit-Queue: David Grogan <dgrogan@chromium.org>
Reviewed-by: default avatarChristian Biesinger <cbiesinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#547599}
parent 292df166
......@@ -429,6 +429,8 @@ blink_core_sources("layout") {
"ng/ng_container_fragment_builder.h",
"ng/ng_exclusion.cc",
"ng/ng_exclusion.h",
"ng/ng_flex_layout_algorithm.cc",
"ng/ng_flex_layout_algorithm.h",
"ng/ng_floats_utils.cc",
"ng/ng_floats_utils.h",
"ng/ng_fragment.cc",
......
......@@ -32,6 +32,7 @@
#include "core/layout/LayoutBox.h"
#include "core/layout/MinMaxSize.h"
#include "core/layout/ng/ng_layout_result.h"
namespace blink {
......@@ -47,7 +48,8 @@ FlexItem::FlexItem(LayoutBox* box,
min_max_sizes.ClampSizeToMinAndMax(flex_base_content_size)),
main_axis_border_and_padding(main_axis_border_and_padding),
main_axis_margin(main_axis_margin),
frozen(false) {
frozen(false),
ng_input_node(/* LayoutBox* */ nullptr) {
DCHECK(!box->IsOutOfFlowPositioned());
DCHECK_GE(min_max_sizes.max_size, LayoutUnit())
<< "Use LayoutUnit::Max() for no max size";
......
......@@ -35,6 +35,7 @@
#include "core/CoreExport.h"
#include "core/layout/MinMaxSize.h"
#include "core/layout/OrderIterator.h"
#include "core/layout/ng/ng_layout_input_node.h"
#include "core/style/ComputedStyle.h"
#include "platform/LayoutUnit.h"
#include "platform/geometry/LayoutPoint.h"
......@@ -44,6 +45,7 @@ namespace blink {
class FlexLayoutAlgorithm;
class LayoutBox;
class NGLayoutResult;
struct MinMaxSize;
enum FlexSign {
......@@ -120,6 +122,10 @@ class FlexItem {
LayoutPoint desired_location;
bool frozen;
// TODO(dgrogan): Change this to NGBlockNode when all items are blockified.
NGLayoutInputNode ng_input_node;
scoped_refptr<NGLayoutResult> layout_result;
};
class FlexLine {
......
......@@ -37,6 +37,7 @@
#include "core/layout/LayoutView.h"
#include "core/layout/MinMaxSize.h"
#include "core/layout/TextAutosizer.h"
#include "core/layout/ng/ng_layout_result.h"
#include "core/paint/BlockPainter.h"
#include "core/paint/PaintLayer.h"
#include "core/style/ComputedStyle.h"
......
......@@ -271,6 +271,11 @@ LayoutObject* LayoutObject::CreateObject(Element* element,
return new LayoutDeprecatedFlexibleBox(*element);
case EDisplay::kFlex:
case EDisplay::kInlineFlex:
if (RuntimeEnabledFeatures::LayoutNGFlexBoxEnabled() &&
ShouldUseNewLayout(style)) {
// TODO(dgrogan): Change this to new class LayoutNGFlex.
return new LayoutNGBlockFlow(element);
}
return new LayoutFlexibleBox(element);
case EDisplay::kGrid:
case EDisplay::kInlineGrid:
......
......@@ -21,6 +21,7 @@
#include "core/layout/ng/ng_column_layout_algorithm.h"
#include "core/layout/ng/ng_constraint_space.h"
#include "core/layout/ng/ng_constraint_space_builder.h"
#include "core/layout/ng/ng_flex_layout_algorithm.h"
#include "core/layout/ng/ng_fragment_builder.h"
#include "core/layout/ng/ng_fragmentation_utils.h"
#include "core/layout/ng/ng_layout_input_node.h"
......@@ -48,6 +49,8 @@ scoped_refptr<NGLayoutResult> LayoutWithAlgorithm(
const NGConstraintSpace& space,
NGBreakToken* break_token) {
auto* token = ToNGBlockBreakToken(break_token);
if (style.IsDisplayFlexibleBox())
return NGFlexLayoutAlgorithm(node, space, token).Layout();
// If there's a legacy layout box, we can only do block fragmentation if we
// would have done block fragmentation with the legacy engine. Otherwise
// writing data back into the legacy tree will fail. Look for the flow
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/layout/ng/ng_flex_layout_algorithm.h"
#include <algorithm>
#include "core/layout/FlexibleBoxAlgorithm.h"
#include "core/layout/LayoutBox.h"
#include "core/layout/ng/inline/ng_baseline.h"
#include "core/layout/ng/ng_block_layout_algorithm.h"
#include "core/layout/ng/ng_box_fragment.h"
#include "core/layout/ng/ng_constraint_space_builder.h"
#include "core/layout/ng/ng_length_utils.h"
#include "core/layout/ng/ng_out_of_flow_layout_part.h"
#include "core/layout/ng/ng_physical_box_fragment.h"
#include "platform/wtf/Vector.h"
namespace blink {
NGFlexLayoutAlgorithm::NGFlexLayoutAlgorithm(NGBlockNode node,
const NGConstraintSpace& space,
NGBreakToken* break_token)
: NGLayoutAlgorithm(node, space, ToNGBlockBreakToken(break_token)) {}
scoped_refptr<NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
DCHECK(!Style().IsColumnFlexDirection())
<< "Column flexboxes aren't supported yet";
DCHECK(!NeedMinMaxSize(ConstraintSpace(), Style()))
<< "Don't support that yet";
LayoutUnit container_logical_width = ComputeInlineSizeForFragment(
ConstraintSpace(), Style(), /* MinMaxSize */ WTF::nullopt);
Vector<FlexItem> flex_items;
for (NGLayoutInputNode child = Node().FirstChild(); child;
child = child.NextSibling()) {
if (child.IsOutOfFlowPositioned())
continue;
// Assume row flexbox with no orthogonal items, which lets us just use
// MinMaxSize for flex base size. An orthogonal item would need full layout.
DCHECK(IsParallelWritingMode(Node().Style().GetWritingMode(),
child.Style().GetWritingMode()))
<< "Orthogonal items aren't supported yet.";
MinMaxSizeInput zero_input;
MinMaxSize min_max_sizes = child.ComputeMinMaxSize(zero_input);
LayoutUnit flex_base_content_size;
if (child.Style().FlexBasis().IsAuto() && child.Style().Width().IsAuto()) {
flex_base_content_size = min_max_sizes.max_size;
} else {
Length length_to_resolve = child.Style().FlexBasis();
if (length_to_resolve.IsAuto())
length_to_resolve = child.Style().Width();
DCHECK(!length_to_resolve.IsAuto());
// TODO(dgrogan): ResolveInlineLength will handle all the types?
DCHECK(length_to_resolve.IsFixed())
<< "We only support auto and fixed flex base sizes";
flex_base_content_size = LayoutUnit(length_to_resolve.Value());
}
NGConstraintSpaceBuilder space_builder(ConstraintSpace());
// TODO(dgrogan): Set the percentage size also.
space_builder.SetAvailableSize(
NGLogicalSize{container_logical_width, NGSizeIndefinite});
scoped_refptr<NGConstraintSpace> child_space =
space_builder.ToConstraintSpace(child.Style().GetWritingMode());
LayoutUnit main_axis_border_and_padding =
ComputeBorders(*child_space, child.Style()).InlineSum() +
ComputePadding(*child_space, child.Style()).InlineSum();
LayoutUnit main_axis_margin =
ComputeMarginsForSelf(*child_space, child.Style()).InlineSum();
// TODO(dgrogan): When child has a min/max-{width,height} set, call
// Resolve{Inline,Block}Length here with child's style and constraint space.
// Fill this in with the results.
MinMaxSize min_max_sizes_in_main_axis_direction{LayoutUnit(),
LayoutUnit::Max()};
flex_items.emplace_back(ToLayoutBox(Node().GetLayoutObject()),
flex_base_content_size,
min_max_sizes_in_main_axis_direction,
main_axis_border_and_padding, main_axis_margin);
flex_items[flex_items.size() - 1].ng_input_node = child;
}
FlexLayoutAlgorithm algorithm(&Style(), container_logical_width, flex_items);
NGBoxStrut borders_scrollbar_padding =
CalculateBorderScrollbarPadding(ConstraintSpace(), Node());
LayoutUnit main_axis_offset = borders_scrollbar_padding.InlineSum();
LayoutUnit cross_axis_offset = borders_scrollbar_padding.BlockSum();
FlexLine* line;
while ((line = algorithm.ComputeNextFlexLine(container_logical_width))) {
line->SetContainerMainInnerSize(container_logical_width);
line->FreezeInflexibleItems();
while (!line->ResolveFlexibleLengths()) {
continue;
}
for (size_t i = 0; i < line->line_items.size(); ++i) {
FlexItem& flex_item = line->line_items[i];
NGConstraintSpaceBuilder space_builder(ConstraintSpace());
// TODO(dgrogan): Set the percentage size also.
space_builder.SetAvailableSize(
{flex_item.flexed_content_size, NGSizeIndefinite});
space_builder.SetIsFixedSizeInline(true);
scoped_refptr<NGConstraintSpace> child_space =
space_builder.ToConstraintSpace(
flex_item.box->Style()->GetWritingMode());
flex_item.layout_result =
flex_item.ng_input_node.Layout(*child_space, nullptr /*break token*/);
flex_item.cross_axis_size =
flex_item.layout_result->PhysicalFragment()->Size().height;
}
// cross_axis_offset is updated in each iteration of the loop, for passing
// in to the next iteration.
line->ComputeLineItemsPosition(main_axis_offset, cross_axis_offset);
for (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): This line is only needed because we erroneously tell the
// parent block layout algorithm that the flexbox doesn't create a new BFC, so
// a DCHECK is triggered. Remove this line after adding a LayoutNGFlexibleBox
// class and returning it from LayoutObject::CreateLayoutObject().
container_builder_.SetExclusionSpace(
std::make_unique<NGExclusionSpace>(ConstraintSpace().ExclusionSpace()));
return container_builder_.ToBoxFragment();
}
Optional<MinMaxSize> NGFlexLayoutAlgorithm::ComputeMinMaxSize(
const MinMaxSizeInput& input) const {
// TODO(dgrogan): Implement this.
return WTF::nullopt;
}
} // namespace blink
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ng_flex_layout_algorithm_h
#define ng_flex_layout_algorithm_h
#include "core/layout/ng/ng_layout_algorithm.h"
#include "core/layout/ng/ng_fragment_builder.h"
namespace blink {
class NGBlockNode;
class NGBlockBreakToken;
class NGBreakToken;
class NGConstraintSpace;
class CORE_EXPORT NGFlexLayoutAlgorithm
: public NGLayoutAlgorithm<NGBlockNode,
NGFragmentBuilder,
NGBlockBreakToken> {
public:
NGFlexLayoutAlgorithm(NGBlockNode, const NGConstraintSpace&, NGBreakToken*);
scoped_refptr<NGLayoutResult> Layout() override;
Optional<MinMaxSize> ComputeMinMaxSize(const MinMaxSizeInput&) const override;
};
} // namespace blink
#endif // ng_flex_layout_algorithm_h
......@@ -590,11 +590,14 @@
},
{
name: "LayoutNG",
implied_by: ["LayoutNGBlockFragmentation"],
implied_by: ["LayoutNGBlockFragmentation", "LayoutNGFlexBox"],
},
{
name: "LayoutNGBlockFragmentation",
},
{
name: "LayoutNGFlexBox",
},
{
name: "LayoutNGFragmentCaching",
},
......
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