summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
blob: 3d82603bf5ed0b5232036857e1cc6c9afbff6386 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// 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 "third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h"

#include <algorithm>
#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/ng/inline/ng_baseline.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/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.back().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