1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_COLUMN_LAYOUT_ALGORITHM_H_
6 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_COLUMN_LAYOUT_ALGORITHM_H_
7 
8 #include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
9 #include "third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h"
10 
11 namespace blink {
12 
13 enum class NGBreakStatus;
14 class NGBlockNode;
15 class NGBlockBreakToken;
16 class NGConstraintSpace;
17 struct LogicalSize;
18 struct NGMarginStrut;
19 
20 class CORE_EXPORT NGColumnLayoutAlgorithm
21     : public NGLayoutAlgorithm<NGBlockNode,
22                                NGBoxFragmentBuilder,
23                                NGBlockBreakToken> {
24  public:
25   NGColumnLayoutAlgorithm(const NGLayoutAlgorithmParams& params);
26 
27   scoped_refptr<const NGLayoutResult> Layout() override;
28 
29   base::Optional<MinMaxSizes> ComputeMinMaxSizes(
30       const MinMaxSizesInput&) const override;
31 
32  private:
33   // Lay out as many children as we can. If |kNeedsEarlierBreak| is returned, it
34   // means that we ran out of space at an unappealing location, and need to
35   // relayout and break earlier (because we have a better breakpoint there). If
36   // |kBrokeBefore| is returned, it means that we need to break before the
37   // multicol container, and retry in the next fragmentainer.
38   NGBreakStatus LayoutChildren();
39 
40   // Lay out one row of columns. The layout result returned is for the last
41   // column that was laid out. The rows themselves don't create fragments. If
42   // we're in a nested fragmentation context and completely out of outer
43   // fragmentainer space, nullptr will be returned.
44   scoped_refptr<const NGLayoutResult> LayoutRow(
45       const NGBlockBreakToken* next_column_token,
46       NGMarginStrut*);
47 
48   // Lay out a column spanner. The return value will tell whether to break
49   // before the spanner or not. If we're not to break before the spanner, but
50   // rather inside, |spanner_break_token| will be set, so that we know where to
51   // resume in the next outer fragmentainer. If |NGBreakStatus::kContinue| is
52   // returned, and no break token was set, it means that we can proceed to the
53   // next row of columns.
54   NGBreakStatus LayoutSpanner(NGBlockNode spanner_node,
55                               const NGBlockBreakToken* break_token,
56                               NGMarginStrut*,
57                               scoped_refptr<const NGBlockBreakToken>*);
58 
59   LayoutUnit CalculateBalancedColumnBlockSize(
60       const LogicalSize& column_size,
61       const NGBlockBreakToken* child_break_token);
62 
63   // Stretch the column length. We do this during column balancing, when we
64   // discover that the current length isn't large enough to fit all content.
65   LayoutUnit StretchColumnBlockSize(LayoutUnit minimal_space_shortage,
66                                     LayoutUnit current_column_size) const;
67 
68   LayoutUnit ConstrainColumnBlockSize(LayoutUnit size) const;
CurrentContentBlockOffset()69   LayoutUnit CurrentContentBlockOffset() const {
70     return intrinsic_block_size_ - border_scrollbar_padding_.block_start;
71   }
72 
73   // Finalize layout after breaking before column contents.
74   void FinishAfterBreakBeforeRow(
75       scoped_refptr<const NGBlockBreakToken> next_column_token);
76 
77   // Finalize layout after breaking before a spanner.
78   void FinishAfterBreakBeforeSpanner(
79       scoped_refptr<const NGBlockBreakToken> next_column_token);
80 
81   // Lay out again, this time with a predefined good breakpoint that we
82   // discovered in the first pass. This happens when we run out of space in a
83   // fragmentainer at an less-than-ideal location, due to breaking restrictions,
84   // such as break-before:avoid or break-after:avoid.
85   scoped_refptr<const NGLayoutResult> RelayoutAndBreakEarlier();
86 
87   NGConstraintSpace CreateConstraintSpaceForColumns(
88       const LogicalSize& column_size,
89       bool is_first_fragmentainer,
90       bool balance_columns) const;
91   NGConstraintSpace CreateConstraintSpaceForBalancing(
92       const LogicalSize& column_size) const;
93   NGConstraintSpace CreateConstraintSpaceForSpanner(
94       const NGBlockNode& spanner,
95       LayoutUnit block_offset) const;
96   NGConstraintSpace CreateConstraintSpaceForMinMax() const;
97 
98   // When set, this will specify where to break before or inside.
99   const NGEarlyBreak* early_break_ = nullptr;
100 
101   // Border + padding sum, resolved from the node's computed style.
102   const NGBoxStrut border_padding_;
103 
104   // Border + scrollbar + padding sum for the fragment to be generated (most
105   // importantly, for non-first fragments, leading block border + scrollbar +
106   // padding is zero).
107   NGBoxStrut border_scrollbar_padding_;
108 
109   LogicalSize content_box_size_;
110   int used_column_count_;
111   LayoutUnit column_inline_size_;
112   LayoutUnit column_inline_progression_;
113   LayoutUnit intrinsic_block_size_;
114   bool is_constrained_by_outer_fragmentation_context_ = false;
115 
116   // This will be set during (outer) block fragmentation once we've processed
117   // the first piece of content of the multicol container. It is used to check
118   // if we're at a valid class A  breakpoint (between block-level siblings).
119   bool has_processed_first_child_ = false;
120 };
121 
122 }  // namespace blink
123 
124 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_COLUMN_LAYOUT_ALGORITHM_H_
125