summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
blob: 70a65583772f5f99d6635f217f9fe3015b8b4a80 (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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
// Copyright 2016 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 THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_LAYOUT_INPUT_NODE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_LAYOUT_INPUT_NODE_H_

#include "base/dcheck_is_on.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
#include "third_party/blink/renderer/core/layout/geometry/axis.h"
#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/ng/layout_box_utils.h"
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
#include "third_party/blink/renderer/platform/text/writing_mode.h"

namespace blink {

class ComputedStyle;
class DisplayLockContext;
class Document;
class LayoutObject;
class LayoutBox;
struct MinMaxSizes;
struct PhysicalSize;

// The input to the min/max inline size calculation algorithm for child nodes.
// Child nodes within the same formatting context need to know which floats are
// beside them.
struct MinMaxSizesFloatInput {
  explicit MinMaxSizesFloatInput() = default;
  LayoutUnit float_left_inline_size;
  LayoutUnit float_right_inline_size;
};

// The output of the min/max inline size calculation algorithm. Contains the
// min/max sizes, and if this calculation will change if the block constraints
// change.
struct MinMaxSizesResult {
  MinMaxSizesResult() = default;
  MinMaxSizesResult(MinMaxSizes sizes, bool depends_on_block_constraints)
      : sizes(sizes),
        depends_on_block_constraints(depends_on_block_constraints) {}

  MinMaxSizes sizes;
  bool depends_on_block_constraints = false;
};

// Represents the input to a layout algorithm for a given node. The layout
// engine should use the style, node type to determine which type of layout
// algorithm to use to produce fragments for this node.
class CORE_EXPORT NGLayoutInputNode {
  DISALLOW_NEW();

 public:
  enum NGLayoutInputNodeType {
    kBlock,
    kInline
    // When adding new values, ensure type_ below has enough bits.
  };

  static NGLayoutInputNode Create(LayoutBox* box, NGLayoutInputNodeType type) {
    // This function should create an instance of the subclass. This works
    // because subclasses are not virtual and do not add fields.
    return NGLayoutInputNode(box, type);
  }

  NGLayoutInputNode(std::nullptr_t) : box_(nullptr), type_(kBlock) {}

  NGLayoutInputNodeType Type() const {
    return static_cast<NGLayoutInputNodeType>(type_);
  }
  bool IsInline() const { return type_ == kInline; }
  bool IsBlock() const { return type_ == kBlock; }

  bool IsBlockFlow() const { return IsBlock() && box_->IsLayoutBlockFlow(); }
  bool IsLayoutNGCustom() const {
    return IsBlock() && box_->IsLayoutNGCustom();
  }
  bool IsColumnSpanAll() const { return IsBlock() && box_->IsColumnSpanAll(); }
  bool IsFloating() const { return IsBlock() && box_->IsFloating(); }
  bool IsOutOfFlowPositioned() const {
    return IsBlock() && box_->IsOutOfFlowPositioned();
  }
  bool IsFloatingOrOutOfFlowPositioned() const {
    return IsFloating() || IsOutOfFlowPositioned();
  }
  bool IsReplaced() const { return box_->IsLayoutReplaced(); }
  bool IsFrame() const { return box_->IsFrame(); }
  bool IsAbsoluteContainer() const {
    return box_->CanContainAbsolutePositionObjects();
  }
  bool IsFixedContainer() const {
    return box_->CanContainFixedPositionObjects();
  }
  bool IsBody() const { return IsBlock() && box_->IsBody(); }
  bool IsDocumentElement() const { return box_->IsDocumentElement(); }
  bool IsFlexItem() const { return IsBlock() && box_->IsFlexItemIncludingNG(); }
  bool IsFlexibleBox() const {
    return IsBlock() && box_->IsFlexibleBoxIncludingNG();
  }
  bool IsGrid() const { return IsBlock() && box_->IsLayoutGridIncludingNG(); }
  bool ShouldBeConsideredAsReplaced() const {
    return box_->ShouldBeConsideredAsReplaced();
  }
  bool IsListItem() const { return IsBlock() && box_->IsLayoutNGListItem(); }
  // Returns the list marker if |this.IsListItem()| with an outside list marker.
  // Otherwise |nullptr|.
  NGBlockNode ListMarkerBlockNodeIfListItem() const;
  bool IsListMarker() const {
    return IsBlock() && box_->IsLayoutNGOutsideListMarker();
  }
  bool ListMarkerOccupiesWholeLine() const {
    DCHECK(IsListMarker());
    return To<LayoutNGOutsideListMarker>(box_)->NeedsOccupyWholeLine();
  }
  bool IsButton() const { return IsBlock() && box_->IsLayoutNGButton(); }
  bool IsFieldsetContainer() const {
    return IsBlock() && box_->IsLayoutNGFieldset();
  }
  bool IsRubyRun() const { return IsBlock() && box_->IsRubyRun(); }
  bool IsRubyText() const { return box_->IsRubyText(); }

  // Return true if this is the legend child of a fieldset that gets special
  // treatment (i.e. placed over the block-start border).
  bool IsRenderedLegend() const {
    return IsBlock() && box_->IsRenderedLegend();
  }
  // Return true if this node is for <input type=range>.
  bool IsSlider() const;
  // Return true if this node is for a slider thumb in <input type=range>.
  bool IsSliderThumb() const;
  bool IsSVGText() const;
  bool IsTable() const { return IsBlock() && box_->IsTable(); }
  bool IsNGTable() const { return IsTable() && box_->IsLayoutNGMixin(); }

  bool IsTableCaption() const { return IsBlock() && box_->IsTableCaption(); }

  // Section with empty rows is considered empty.
  bool IsEmptyTableSection() const;

  bool IsTableCol() const {
    return Style().Display() == EDisplay::kTableColumn;
  }

  bool IsTableColgroup() const {
    return Style().Display() == EDisplay::kTableColumnGroup;
  }

  wtf_size_t TableColumnSpan() const;

  wtf_size_t TableCellColspan() const;

  wtf_size_t TableCellRowspan() const;

  bool IsTextArea() const { return box_->IsTextAreaIncludingNG(); }
  bool IsTextControl() const { return box_->IsTextControlIncludingNG(); }
  bool IsTextControlPlaceholder() const;
  bool IsTextField() const { return box_->IsTextFieldIncludingNG(); }

  bool IsMathRoot() const { return box_->IsMathMLRoot(); }
  bool IsMathML() const { return box_->IsMathML(); }

  bool IsAnonymousBlock() const { return box_->IsAnonymousBlock(); }

  // If the node is a quirky container for margin collapsing, see:
  // https://html.spec.whatwg.org/C/#margin-collapsing-quirks
  // NOTE: The spec appears to only somewhat match reality.
  bool IsQuirkyContainer() const {
    return box_->GetDocument().InQuirksMode() &&
           (box_->IsBody() || box_->IsTableCell());
  }

  // Return true if this node is monolithic for block fragmentation.
  bool IsMonolithic() const {
    // Lines are always monolithic. We cannot block-fragment inside them.
    if (IsInline())
      return true;
    return box_->GetNGPaginationBreakability() == LayoutBox::kForbidBreaks;
  }

  bool IsScrollContainer() const {
    return IsBlock() && box_->IsScrollContainer();
  }

  bool CreatesNewFormattingContext() const {
    return IsBlock() && box_->CreatesNewFormattingContext();
  }

  // Returns true if this node should pass its percentage resolution block-size
  // to its children. Typically only quirks-mode, auto block-size, block nodes.
  bool UseParentPercentageResolutionBlockSizeForChildren() const {
    auto* layout_block = DynamicTo<LayoutBlock>(box_);
    if (IsBlock() && layout_block) {
      return LayoutBoxUtils::SkipContainingBlockForPercentHeightCalculation(
          layout_block);
    }

    return false;
  }

  // Returns intrinsic sizing information for replaced elements.
  // ComputeReplacedSize can use it to compute actual replaced size.
  // Corresponds to Legacy's LayoutReplaced::IntrinsicSizingInfo.
  // Use NGBlockNode::GetAspectRatio to get the aspect ratio.
  void IntrinsicSize(absl::optional<LayoutUnit>* computed_inline_size,
                     absl::optional<LayoutUnit>* computed_block_size) const;

  // Returns the next sibling.
  NGLayoutInputNode NextSibling() const;

  Document& GetDocument() const { return box_->GetDocument(); }

  Node* GetDOMNode() const { return box_->GetNode(); }

  PhysicalSize InitialContainingBlockSize() const;

  // Returns the LayoutObject which is associated with this node.
  LayoutBox* GetLayoutBox() const { return box_; }

  const ComputedStyle& Style() const { return box_->StyleRef(); }

  bool ShouldApplySizeContainment() const {
    return box_->ShouldApplySizeContainment();
  }
  // Return true if we should apply at least inline-size containment
  // (i.e. "contain" is "size" or "inline-size").
  bool ShouldApplyInlineSizeContainment() const {
    return box_->ShouldApplyInlineSizeContainment();
  }
  // Return true if we should apply at least block-size containment
  // (i.e. "contain" is "size" or "block-size").
  bool ShouldApplyBlockSizeContainment() const {
    return box_->ShouldApplyBlockSizeContainment();
  }

  bool IsContainerForContainerQueries() const {
    return box_->IsContainerForContainerQueries();
  }

  LogicalAxes ContainedAxes() const {
    LogicalAxes axes(kLogicalAxisNone);
    if (ShouldApplyInlineSizeContainment())
      axes |= LogicalAxes(kLogicalAxisInline);
    if (ShouldApplyBlockSizeContainment())
      axes |= LogicalAxes(kLogicalAxisBlock);
    return axes;
  }

  // CSS defines certain cases to synthesize inline block baselines from box.
  // See comments in UseLogicalBottomMarginEdgeForInlineBlockBaseline().
  bool UseBlockEndMarginEdgeForInlineBlockBaseline() const {
    if (auto* layout_box = DynamicTo<LayoutBlock>(GetLayoutBox()))
      return layout_box->UseLogicalBottomMarginEdgeForInlineBlockBaseline();
    return false;
  }

  // CSS intrinsic sizing getters.
  // https://drafts.csswg.org/css-sizing-4/#intrinsic-size-override
  // Note that this returns kIndefiniteSize if the override was not specified.
  LayoutUnit OverrideIntrinsicContentInlineSize() const {
    if (box_->HasOverrideIntrinsicContentLogicalWidth())
      return box_->OverrideIntrinsicContentLogicalWidth();
    return kIndefiniteSize;
  }
  // Note that this returns kIndefiniteSize if the override was not specified.
  LayoutUnit OverrideIntrinsicContentBlockSize() const {
    if (box_->HasOverrideIntrinsicContentLogicalHeight())
      return box_->OverrideIntrinsicContentLogicalHeight();
    return kIndefiniteSize;
  }

  LayoutUnit DefaultIntrinsicContentInlineSize() const {
    return box_->DefaultIntrinsicContentInlineSize();
  }
  LayoutUnit DefaultIntrinsicContentBlockSize() const {
    return box_->DefaultIntrinsicContentBlockSize();
  }

  // Display locking functionality.
  const DisplayLockContext& GetDisplayLockContext() const {
    DCHECK(box_->GetDisplayLockContext());
    return *box_->GetDisplayLockContext();
  }
  bool ChildLayoutBlockedByDisplayLock() const {
    return box_->ChildLayoutBlockedByDisplayLock();
  }

  CustomLayoutChild* GetCustomLayoutChild() const {
    // TODO(ikilpatrick): Support NGInlineNode.
    DCHECK(IsBlock());
    return box_->GetCustomLayoutChild();
  }

  // Return whether we can directly traverse fragments generated from this node
  // (for painting, hit-testing and other layout read operations). If false is
  // returned, we need to traverse the layout object tree instead.
  bool CanTraversePhysicalFragments() const {
    return box_->CanTraversePhysicalFragments();
  }

  String ToString() const;

  explicit operator bool() const { return box_ != nullptr; }

  bool operator==(const NGLayoutInputNode& other) const {
    return box_ == other.box_;
  }

  bool operator!=(const NGLayoutInputNode& other) const {
    return !(*this == other);
  }

#if DCHECK_IS_ON()
  void ShowNodeTree() const;
#endif

 protected:
  NGLayoutInputNode(LayoutBox* box, NGLayoutInputNodeType type)
      : box_(box), type_(type) {}

  void GetOverrideIntrinsicSize(
      absl::optional<LayoutUnit>* computed_inline_size,
      absl::optional<LayoutUnit>* computed_block_size) const;

  LayoutBox* box_;

  unsigned type_ : 1;  // NGLayoutInputNodeType
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_LAYOUT_INPUT_NODE_H_