1 // Copyright 2016 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_CONSTRAINT_SPACE_H_
6 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_CONSTRAINT_SPACE_H_
7 
8 #include "base/optional.h"
9 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
10 #include "third_party/blink/renderer/core/core_export.h"
11 #include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
12 #include "third_party/blink/renderer/core/layout/geometry/physical_size.h"
13 #include "third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h"
14 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_offset.h"
15 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h"
16 #include "third_party/blink/renderer/core/layout/ng/ng_break_appeal.h"
17 #include "third_party/blink/renderer/core/layout/ng/ng_floats_utils.h"
18 #include "third_party/blink/renderer/core/layout/ng/table/ng_table_constraint_space_data.h"
19 #include "third_party/blink/renderer/platform/text/text_direction.h"
20 #include "third_party/blink/renderer/platform/text/writing_mode.h"
21 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
22 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
23 
24 namespace blink {
25 
26 class LayoutBlock;
27 class NGConstraintSpaceBuilder;
28 
29 enum NGFragmentationType {
30   kFragmentNone,
31   kFragmentPage,
32   kFragmentColumn,
33   kFragmentRegion
34 };
35 
36 // "adjoining" objects (either floats or inline-level OOF-positioned nodes) are
37 // used to indicate that a particular node might need a relayout once its BFC
38 // block-offset is resvoled. E.g. their position depends on the final BFC
39 // block-offset being known.
40 enum NGAdjoiningObjectTypeValue {
41   kAdjoiningNone = 0b000,
42   kAdjoiningFloatLeft = 0b001,
43   kAdjoiningFloatRight = 0b010,
44   kAdjoiningFloatBoth = 0b011,
45   kAdjoiningInlineOutOfFlow = 0b100
46 };
47 typedef int NGAdjoiningObjectTypes;
48 
49 // Tables have two passes, a "measure" pass (for determining the table row
50 // height), and a "layout" pass.
51 // See: https://drafts.csswg.org/css-tables-3/#row-layout
52 //
53 // This enum is used for communicating to *direct* children of table cells,
54 // which layout mode the table cell is in.
55 enum class NGTableCellChildLayoutMode {
56   kNotTableCellChild,  // The node isn't a table cell child.
57   kMeasure,            // A table cell child, in the "measure" mode.
58   kMeasureRestricted,  // A table cell child, in the "restricted-measure" mode.
59   kLayout              // A table cell child, in the "layout" mode.
60 };
61 
62 // Some layout algorithms (flow, tables) calculate their alignment baseline
63 // differently if they are within an atomic-inline context.
64 //
65 // Other more modern layout algorithms (flex, grid) however ignore this flag
66 // and always calculate the alignment baseline in the same way (returning the
67 // "first-line").
68 enum class NGBaselineAlgorithmType {
69   // Compute the baseline of the first line box.
70   kFirstLine,
71   // Compute the baseline(s) for when we are within an inline-block context. If
72   // the child is block-flow it will produce both the first, and last baselines.
73   kInlineBlock
74 };
75 
76 // Some layout algorithms have multiple layout passes. Between passes they
77 // typically have different results which we need to cache separately for
78 // performance reasons.
79 //
80 // This enum gives the caching logic a hint into which cache "slot" it should
81 // store a result in.
82 enum class NGCacheSlot { kLayout, kMeasure };
83 
84 // The NGConstraintSpace represents a set of constraints and available space
85 // which a layout algorithm may produce a NGFragment within.
86 class CORE_EXPORT NGConstraintSpace final {
87   USING_FAST_MALLOC(NGConstraintSpace);
88 
89  public:
90   // Percentages are frequently the same as the available-size, zero, or
91   // indefinite (thanks non-quirks mode)! This enum encodes this information.
92   enum NGPercentageStorage {
93     kSameAsAvailable,
94     kZero,
95     kIndefinite,
96     kRareDataPercentage
97   };
98 
99   // To ensure that the bfc_offset_, rare_data_ union doesn't get polluted,
100   // always initialize the bfc_offset_.
NGConstraintSpace()101   NGConstraintSpace() : bfc_offset_() {}
102 
NGConstraintSpace(const NGConstraintSpace & other)103   NGConstraintSpace(const NGConstraintSpace& other)
104       : available_size_(other.available_size_),
105         exclusion_space_(other.exclusion_space_),
106         bitfields_(other.bitfields_) {
107     if (HasRareData())
108       rare_data_ = new RareData(*other.rare_data_);
109     else
110       bfc_offset_ = other.bfc_offset_;
111   }
NGConstraintSpace(NGConstraintSpace && other)112   NGConstraintSpace(NGConstraintSpace&& other)
113       : available_size_(other.available_size_),
114         exclusion_space_(std::move(other.exclusion_space_)),
115         bitfields_(other.bitfields_) {
116     if (HasRareData()) {
117       rare_data_ = other.rare_data_;
118       other.rare_data_ = nullptr;
119     } else {
120       bfc_offset_ = other.bfc_offset_;
121     }
122   }
123 
124   NGConstraintSpace& operator=(const NGConstraintSpace& other) {
125     available_size_ = other.available_size_;
126     if (HasRareData())
127       delete rare_data_;
128     if (other.HasRareData())
129       rare_data_ = new RareData(*other.rare_data_);
130     else
131       bfc_offset_ = other.bfc_offset_;
132     exclusion_space_ = other.exclusion_space_;
133     bitfields_ = other.bitfields_;
134     return *this;
135   }
136   NGConstraintSpace& operator=(NGConstraintSpace&& other) {
137     available_size_ = other.available_size_;
138     if (HasRareData())
139       delete rare_data_;
140     if (other.HasRareData()) {
141       rare_data_ = other.rare_data_;
142       other.rare_data_ = nullptr;
143     } else {
144       bfc_offset_ = other.bfc_offset_;
145     }
146     exclusion_space_ = std::move(other.exclusion_space_);
147     bitfields_ = other.bitfields_;
148     return *this;
149   }
150 
~NGConstraintSpace()151   ~NGConstraintSpace() {
152     if (HasRareData())
153       delete rare_data_;
154   }
155 
156   // Creates NGConstraintSpace representing LayoutObject's containing block.
157   // This should live on NGBlockNode or another layout bridge and probably take
158   // a root NGConstraintSpace.
159   static NGConstraintSpace CreateFromLayoutObject(const LayoutBlock&);
160 
ExclusionSpace()161   const NGExclusionSpace& ExclusionSpace() const { return exclusion_space_; }
162 
Direction()163   TextDirection Direction() const {
164     return static_cast<TextDirection>(bitfields_.direction);
165   }
166 
GetWritingMode()167   WritingMode GetWritingMode() const {
168     return static_cast<WritingMode>(bitfields_.writing_mode);
169   }
170 
GetWritingDirection()171   WritingDirectionMode GetWritingDirection() const {
172     return {GetWritingMode(), Direction()};
173   }
174 
IsOrthogonalWritingModeRoot()175   bool IsOrthogonalWritingModeRoot() const {
176     return bitfields_.is_orthogonal_writing_mode_root;
177   }
178 
179   // The available space size.
180   // See: https://drafts.csswg.org/css-sizing/#available
AvailableSize()181   LogicalSize AvailableSize() const { return available_size_; }
182 
183   // The size to use for percentage resolution.
184   // See: https://drafts.csswg.org/css-sizing/#percentage-sizing
PercentageResolutionInlineSize()185   LayoutUnit PercentageResolutionInlineSize() const {
186     switch (static_cast<NGPercentageStorage>(
187         bitfields_.percentage_inline_storage)) {
188       default:
189         NOTREACHED();
190         U_FALLTHROUGH;
191       case kSameAsAvailable:
192         return available_size_.inline_size;
193       case kZero:
194         return LayoutUnit();
195       case kIndefinite:
196         return kIndefiniteSize;
197       case kRareDataPercentage:
198         DCHECK(HasRareData());
199         return rare_data_->percentage_resolution_size.inline_size;
200     }
201   }
202 
PercentageResolutionBlockSize()203   LayoutUnit PercentageResolutionBlockSize() const {
204     switch (
205         static_cast<NGPercentageStorage>(bitfields_.percentage_block_storage)) {
206       default:
207         NOTREACHED();
208         U_FALLTHROUGH;
209       case kSameAsAvailable:
210         return available_size_.block_size;
211       case kZero:
212         return LayoutUnit();
213       case kIndefinite:
214         return kIndefiniteSize;
215       case kRareDataPercentage:
216         DCHECK(HasRareData());
217         return rare_data_->percentage_resolution_size.block_size;
218     }
219   }
220 
PercentageResolutionSize()221   LogicalSize PercentageResolutionSize() const {
222     return {PercentageResolutionInlineSize(), PercentageResolutionBlockSize()};
223   }
224 
ReplacedPercentageResolutionInlineSize()225   LayoutUnit ReplacedPercentageResolutionInlineSize() const {
226     return PercentageResolutionInlineSize();
227   }
228 
ReplacedPercentageResolutionBlockSize()229   LayoutUnit ReplacedPercentageResolutionBlockSize() const {
230     switch (static_cast<NGPercentageStorage>(
231         bitfields_.replaced_percentage_block_storage)) {
232       case kSameAsAvailable:
233         return available_size_.block_size;
234       case kZero:
235         return LayoutUnit();
236       case kIndefinite:
237         return kIndefiniteSize;
238       case kRareDataPercentage:
239         DCHECK(HasRareData());
240         return rare_data_->replaced_percentage_resolution_block_size;
241       default:
242         NOTREACHED();
243     }
244 
245     return available_size_.block_size;
246   }
247 
248   // The size to use for percentage resolution of replaced elements.
ReplacedPercentageResolutionSize()249   LogicalSize ReplacedPercentageResolutionSize() const {
250     return {ReplacedPercentageResolutionInlineSize(),
251             ReplacedPercentageResolutionBlockSize()};
252   }
253 
254   // The size to use for percentage resolution for margin/border/padding.
255   // They are always get computed relative to the inline size, in the parent
256   // writing mode.
PercentageResolutionInlineSizeForParentWritingMode()257   LayoutUnit PercentageResolutionInlineSizeForParentWritingMode() const {
258     if (!IsOrthogonalWritingModeRoot())
259       return PercentageResolutionInlineSize();
260     if (PercentageResolutionBlockSize() != kIndefiniteSize)
261       return PercentageResolutionBlockSize();
262     // TODO(mstensho): Figure out why we get here. It seems wrong, but we do get
263     // here in some grid layout situations.
264     return LayoutUnit();
265   }
266 
267   // Inline/block target stretch size constraints.
268   // See:
269   // https://mathml-refresh.github.io/mathml-core/#dfn-inline-stretch-size-constraint
TargetStretchInlineSize()270   LayoutUnit TargetStretchInlineSize() const {
271     return HasRareData() ? rare_data_->TargetStretchInlineSize()
272                          : kIndefiniteSize;
273   }
274 
HasTargetStretchInlineSize()275   bool HasTargetStretchInlineSize() const {
276     return TargetStretchInlineSize() != kIndefiniteSize;
277   }
278 
TargetStretchAscentSize()279   LayoutUnit TargetStretchAscentSize() const {
280     return HasRareData() ? rare_data_->TargetStretchAscentSize()
281                          : kIndefiniteSize;
282   }
283 
HasTargetStretchAscentSize()284   bool HasTargetStretchAscentSize() const {
285     return TargetStretchAscentSize() != kIndefiniteSize;
286   }
287 
TargetStretchDescentSize()288   LayoutUnit TargetStretchDescentSize() const {
289     return HasRareData() ? rare_data_->TargetStretchDescentSize()
290                          : kIndefiniteSize;
291   }
292 
HasTargetStretchDescentSize()293   bool HasTargetStretchDescentSize() const {
294     return TargetStretchDescentSize() != kIndefiniteSize;
295   }
296 
297   // Return the borders which should be used for a table-cell.
TableCellBorders()298   NGBoxStrut TableCellBorders() const {
299     return HasRareData() ? rare_data_->TableCellBorders() : NGBoxStrut();
300   }
301 
TableCellColumnIndex()302   wtf_size_t TableCellColumnIndex() const {
303     return HasRareData() ? rare_data_->TableCellColumnIndex() : 0;
304   }
305 
306   // Return the "intrinsic" padding for a table-cell.
TableCellIntrinsicPadding()307   NGBoxStrut TableCellIntrinsicPadding() const {
308     return HasRareData() ? rare_data_->TableCellIntrinsicPadding()
309                          : NGBoxStrut();
310   }
311 
312   // Return the baseline offset which the table-cell children should align
313   // their baseline to.
TableCellAlignmentBaseline()314   base::Optional<LayoutUnit> TableCellAlignmentBaseline() const {
315     return HasRareData() ? rare_data_->TableCellAlignmentBaseline()
316                          : base::nullopt;
317   }
318 
IsTableCellHiddenForPaint()319   bool IsTableCellHiddenForPaint() const {
320     return HasRareData() ? rare_data_->IsTableCellHiddenForPaint() : false;
321   }
322 
IsTableCellWithCollapsedBorders()323   bool IsTableCellWithCollapsedBorders() const {
324     return HasRareData() ? rare_data_->IsTableCellWithCollapsedBorders()
325                          : false;
326   }
327 
TableData()328   const NGTableConstraintSpaceData* TableData() const {
329     return HasRareData() ? rare_data_->TableData() : nullptr;
330   }
331 
TableRowIndex()332   wtf_size_t TableRowIndex() const {
333     return HasRareData() ? rare_data_->TableRowIndex() : kNotFound;
334   }
335 
TableSectionIndex()336   wtf_size_t TableSectionIndex() const {
337     return HasRareData() ? rare_data_->TableSectionIndex() : kNotFound;
338   }
339 
FragmentainerBlockSize()340   LayoutUnit FragmentainerBlockSize() const {
341     return HasRareData() ? rare_data_->fragmentainer_block_size
342                          : kIndefiniteSize;
343   }
344 
345   // Return true if we're column-balancing, and are in the initial pass where
346   // we're calculating the initial minimal column block-size.
IsInitialColumnBalancingPass()347   bool IsInitialColumnBalancingPass() const {
348     return BlockFragmentationType() == kFragmentColumn &&
349            FragmentainerBlockSize() == kIndefiniteSize;
350   }
351 
352   // Return true if we're block-fragmented and know our fragmentainer
353   // block-size.
HasKnownFragmentainerBlockSize()354   bool HasKnownFragmentainerBlockSize() const {
355     if (!HasBlockFragmentation() || IsInitialColumnBalancingPass())
356       return false;
357     // The only case where we allow an unknown fragmentainer block-size is if
358     // we're in the initial column balancing pass.
359     DCHECK(FragmentainerBlockSize() != kIndefiniteSize);
360     return true;
361   }
362 
363   // Return the block-offset from the block-start of the fragmentainer
364   // relative to the block-start of the current block formatting context in
365   // the current fragmentainer. Note that if the current block formatting
366   // context starts in a previous fragmentainer, we'll return the block-offset
367   // relative to the current fragmentainer.
FragmentainerOffsetAtBfc()368   LayoutUnit FragmentainerOffsetAtBfc() const {
369     DCHECK(HasBlockFragmentation());
370     if (HasRareData())
371       return rare_data_->fragmentainer_offset_at_bfc;
372     return LayoutUnit();
373   }
374 
375   // Whether the current constraint space is for the newly established
376   // Formatting Context.
IsNewFormattingContext()377   bool IsNewFormattingContext() const {
378     return bitfields_.is_new_formatting_context;
379   }
380 
381   // Whether the current node is a table-cell.
IsTableCell()382   bool IsTableCell() const { return bitfields_.is_table_cell; }
383 
384   // True if node is either LayoutTableCell or LayoutNGTableCellLegacy
IsLegacyTableCell()385   bool IsLegacyTableCell() const { return bitfields_.is_legacy_table_cell; }
386 
387   // Whether the table-cell fragment should be hidden (not painted) if it has
388   // no children.
HideTableCellIfEmpty()389   bool HideTableCellIfEmpty() const {
390     return HasRareData() && rare_data_->hide_table_cell_if_empty;
391   }
392 
393   // Whether the fragment produced from layout should be anonymous, (e.g. it
394   // may be a column in a multi-column layout). In such cases it shouldn't have
395   // any borders or padding.
IsAnonymous()396   bool IsAnonymous() const { return bitfields_.is_anonymous; }
397 
398   // Whether to use the ':first-line' style or not.
399   // Note, this is not about the first line of the content to layout, but
400   // whether the constraint space itself is on the first line, such as when it's
401   // an inline block.
402   // Also note this is true only when the document has ':first-line' rules.
UseFirstLineStyle()403   bool UseFirstLineStyle() const { return bitfields_.use_first_line_style; }
404 
405   // Returns true if an ancestor had clearance past adjoining floats.
406   //
407   // Typically this can be detected by seeing if a |ForcedBfcBlockOffset| is
408   // set. However new formatting contexts may require additional passes (if
409   // margins are adjoining or not), and without this extra bit of information
410   // can get into a bad state.
AncestorHasClearancePastAdjoiningFloats()411   bool AncestorHasClearancePastAdjoiningFloats() const {
412     return bitfields_.ancestor_has_clearance_past_adjoining_floats;
413   }
414 
415   // Returns if the parent layout needs the baseline from this layout.
416   //
417   // This bit is only used for skipping querying baseline information from
418   // legacy layout.
NeedsBaseline()419   bool NeedsBaseline() const { return bitfields_.needs_baseline; }
420 
421   // How the baseline for the fragment should be calculated, see documentation
422   // for |NGBaselineAlgorithmType|.
BaselineAlgorithmType()423   NGBaselineAlgorithmType BaselineAlgorithmType() const {
424     return static_cast<NGBaselineAlgorithmType>(
425         bitfields_.baseline_algorithm_type);
426   }
427 
428   // Which cache slot the output layout result should be stored in.
CacheSlot()429   NGCacheSlot CacheSlot() const {
430     return static_cast<NGCacheSlot>(bitfields_.cache_slot);
431   }
432 
433   // Some layout modes “stretch” their children to a fixed size (e.g. flex,
434   // grid). These flags represented whether a layout needs to produce a
435   // fragment that satisfies a fixed constraint in the inline and block
436   // direction respectively.
437   //
438   // If these flags are true, the AvailableSize() is interpreted as the fixed
439   // border-box size of this box in the respective dimension.
IsFixedInlineSize()440   bool IsFixedInlineSize() const { return bitfields_.is_fixed_inline_size; }
441 
IsFixedBlockSize()442   bool IsFixedBlockSize() const { return bitfields_.is_fixed_block_size; }
443 
444   // Whether a fixed block-size should be considered indefinite.
IsFixedBlockSizeIndefinite()445   bool IsFixedBlockSizeIndefinite() const {
446     return bitfields_.is_fixed_block_size_indefinite;
447   }
448 
449   // Whether an auto inline-size should be interpreted as shrink-to-fit
450   // (ie. fit-content). This is used for inline-block, floats, etc.
IsShrinkToFit()451   bool IsShrinkToFit() const { return bitfields_.is_shrink_to_fit; }
452 
IsPaintedAtomically()453   bool IsPaintedAtomically() const { return bitfields_.is_painted_atomically; }
454 
455   // If specified a layout should produce a Fragment which fragments at the
456   // blockSize if possible.
BlockFragmentationType()457   NGFragmentationType BlockFragmentationType() const {
458     return HasRareData() ? static_cast<NGFragmentationType>(
459                                rare_data_->block_direction_fragmentation_type)
460                          : kFragmentNone;
461   }
462 
463   // Return true if this constraint space participates in a fragmentation
464   // context.
HasBlockFragmentation()465   bool HasBlockFragmentation() const {
466     return BlockFragmentationType() != kFragmentNone;
467   }
468 
469   // Return true if there's an ancestor multicol container with balanced
470   // columns.
IsInsideBalancedColumns()471   bool IsInsideBalancedColumns() const {
472     return HasRareData() && rare_data_->is_inside_balanced_columns;
473   }
474 
475   // Return true if we're participating in the same block formatting context as
476   // the one established by the nearest ancestor multicol container.
IsInColumnBfc()477   bool IsInColumnBfc() const {
478     return HasRareData() && rare_data_->is_in_column_bfc;
479   }
480 
481   // Get the appeal of the best breakpoint found so far. When progressing
482   // through layout, we know that we don't need to consider less appealing
483   // breakpoints than this.
EarlyBreakAppeal()484   NGBreakAppeal EarlyBreakAppeal() const {
485     if (!HasRareData())
486       return kBreakAppealLastResort;
487     return static_cast<NGBreakAppeal>(rare_data_->early_break_appeal);
488   }
489 
490   // Returns if this node is a table cell child, and which table layout mode
491   // is occurring.
TableCellChildLayoutMode()492   NGTableCellChildLayoutMode TableCellChildLayoutMode() const {
493     return static_cast<NGTableCellChildLayoutMode>(
494         bitfields_.table_cell_child_layout_mode);
495   }
496 
497   // Return true if the block size of the table-cell should be considered
498   // restricted (e.g. height of the cell or its table is non-auto).
IsRestrictedBlockSizeTableCell()499   bool IsRestrictedBlockSizeTableCell() const {
500     return HasRareData() && rare_data_->is_restricted_block_size_table_cell;
501   }
502 
503   // The amount of available space for block-start side annotation.
504   // For the first box, this is the padding-block-start value of the container.
505   // Otherwise, this comes from NGLayoutResult::BlockEndAnnotationSpace().
506   // If the value is negative, it's block-end annotation overflow of the
507   // previous box.
BlockStartAnnotationSpace()508   LayoutUnit BlockStartAnnotationSpace() const {
509     return HasRareData() ? rare_data_->BlockStartAnnotationSpace()
510                          : LayoutUnit();
511   }
512 
MarginStrut()513   NGMarginStrut MarginStrut() const {
514     return HasRareData() ? rare_data_->MarginStrut() : NGMarginStrut();
515   }
516 
517   // The BfcOffset is where the MarginStrut is placed within the block
518   // formatting context.
519   //
520   // The current layout or a descendant layout may "resolve" the BFC offset,
521   // i.e. decide where the current fragment should be placed within the BFC.
522   //
523   // This is done by:
524   //   bfc_block_offset =
525   //     space.BfcOffset().block_offset + space.MarginStrut().Sum();
526   //
527   // The BFC offset can get "resolved" in many circumstances (including, but
528   // not limited to):
529   //   - block_start border or padding in the current layout.
530   //   - Text content, atomic inlines, (see NGLineBreaker).
531   //   - The current layout having a block_size.
532   //   - Clearance before a child.
BfcOffset()533   NGBfcOffset BfcOffset() const {
534     return HasRareData() ? rare_data_->bfc_offset : bfc_offset_;
535   }
536 
537   // If present, and the current layout hasn't resolved its BFC block-offset
538   // yet (see BfcOffset), the layout should position all of its floats at this
539   // offset.
540   //
541   // This value is present if:
542   //   - An ancestor had clearance past adjoining floats. In this case this
543   //     value is calculated ahead of time.
544   //   - A second layout pass is required as there were adjoining-floats
545   //     within the tree, and an arbitrary sibling determined their BFC
546   //     block-offset.
547   //
548   // This value should be propagated to child layouts if the current layout
549   // hasn't resolved its BFC offset yet.
ForcedBfcBlockOffset()550   base::Optional<LayoutUnit> ForcedBfcBlockOffset() const {
551     return HasRareData() ? rare_data_->ForcedBfcBlockOffset() : base::nullopt;
552   }
553 
554   // If present, this is a hint as to where place any adjoining objects. This
555   // isn't necessarily the final position, just where they ended up in a
556   // previous layout pass.
OptimisticBfcBlockOffset()557   base::Optional<LayoutUnit> OptimisticBfcBlockOffset() const {
558     return HasRareData() ? rare_data_->OptimisticBfcBlockOffset()
559                          : base::nullopt;
560   }
561 
562   // The "expected" BFC block-offset is:
563   //  - The |ForcedBfcBlockOffset| if set.
564   //  - The |OptimisticBfcBlockOffset| if set.
565   //  - Otherwise the |BfcOffset|.
566   //
567   // This represents where any adjoining-objects should be placed (potentially
568   // optimistically)
ExpectedBfcBlockOffset()569   LayoutUnit ExpectedBfcBlockOffset() const {
570     // A short-circuit optimization (must equivalent to below).
571     if (!HasRareData()) {
572       DCHECK(!ForcedBfcBlockOffset());
573       DCHECK(!OptimisticBfcBlockOffset());
574       return bfc_offset_.block_offset;
575     }
576 
577     return ForcedBfcBlockOffset().value_or(
578         OptimisticBfcBlockOffset().value_or(BfcOffset().block_offset));
579   }
580 
CustomLayoutData()581   SerializedScriptValue* CustomLayoutData() const {
582     return HasRareData() ? rare_data_->CustomLayoutData() : nullptr;
583   }
584 
585   // Returns the types of preceding adjoining objects.
586   // See |NGAdjoiningObjectTypes|.
587   //
588   // Adjoining floats are positioned at their correct position if the
589   // |ForcedBfcBlockOffset()| is known.
590   //
591   // Adjoining floats should be treated differently when calculating clearance
592   // on a block with adjoining block-start margin (in such cases we will know
593   // up front that the block will need clearance, since, if it doesn't, the
594   // float will be pulled along with the block, and the block will fail to
595   // clear).
AdjoiningObjectTypes()596   NGAdjoiningObjectTypes AdjoiningObjectTypes() const {
597     return bitfields_.adjoining_object_types;
598   }
599 
600   // Return true if there were any earlier floats that may affect the current
601   // layout.
HasFloats()602   bool HasFloats() const { return !ExclusionSpace().IsEmpty(); }
603 
HasClearanceOffset()604   bool HasClearanceOffset() const {
605     return HasRareData() && rare_data_->ClearanceOffset() != LayoutUnit::Min();
606   }
ClearanceOffset()607   LayoutUnit ClearanceOffset() const {
608     return HasRareData() ? rare_data_->ClearanceOffset() : LayoutUnit::Min();
609   }
610 
611   // Return true if this is participating within a -webkit-line-clamp context.
IsLineClampContext()612   bool IsLineClampContext() const { return bitfields_.is_line_clamp_context; }
613 
LinesUntilClamp()614   base::Optional<int> LinesUntilClamp() const {
615     return HasRareData() ? rare_data_->LinesUntilClamp() : base::nullopt;
616   }
617 
618   // Return true if the two constraint spaces are similar enough that it *may*
619   // be possible to skip re-layout. If true is returned, the caller is expected
620   // to verify that any constraint space size (available size, percentage size,
621   // and so on) and BFC offset changes won't require re-layout, before skipping.
MaySkipLayout(const NGConstraintSpace & other)622   bool MaySkipLayout(const NGConstraintSpace& other) const {
623     if (!bitfields_.MaySkipLayout(other.bitfields_))
624       return false;
625 
626     if (!HasRareData() && !other.HasRareData())
627       return true;
628 
629     if (HasRareData() && other.HasRareData())
630       return rare_data_->MaySkipLayout(*other.rare_data_);
631 
632     if (HasRareData())
633       return rare_data_->IsInitialForMaySkipLayout();
634 
635     DCHECK(other.HasRareData());
636     return other.rare_data_->IsInitialForMaySkipLayout();
637   }
638 
639   // Returns true if the size constraints (shrink-to-fit, fixed-inline-size)
640   // are equal.
AreSizeConstraintsEqual(const NGConstraintSpace & other)641   bool AreSizeConstraintsEqual(const NGConstraintSpace& other) const {
642     return bitfields_.AreSizeConstraintsEqual(other.bitfields_);
643   }
644 
AreSizesEqual(const NGConstraintSpace & other)645   bool AreSizesEqual(const NGConstraintSpace& other) const {
646     if (available_size_ != other.available_size_)
647       return false;
648 
649     if (bitfields_.percentage_inline_storage !=
650         other.bitfields_.percentage_inline_storage)
651       return false;
652 
653     if (bitfields_.percentage_block_storage !=
654         other.bitfields_.percentage_block_storage)
655       return false;
656 
657     if (bitfields_.replaced_percentage_block_storage !=
658         other.bitfields_.replaced_percentage_block_storage)
659       return false;
660 
661     // The rest of this method just checks the percentage resolution sizes. If
662     // neither space has rare data, we know that they must equal now.
663     if (!HasRareData() && !other.HasRareData())
664       return true;
665 
666     if (bitfields_.percentage_inline_storage == kRareDataPercentage &&
667         other.bitfields_.percentage_inline_storage == kRareDataPercentage &&
668         rare_data_->percentage_resolution_size.inline_size !=
669             other.rare_data_->percentage_resolution_size.inline_size)
670       return false;
671 
672     if (bitfields_.percentage_block_storage == kRareDataPercentage &&
673         other.bitfields_.percentage_block_storage == kRareDataPercentage &&
674         rare_data_->percentage_resolution_size.block_size !=
675             other.rare_data_->percentage_resolution_size.block_size)
676       return false;
677 
678     if (bitfields_.replaced_percentage_block_storage == kRareDataPercentage &&
679         other.bitfields_.replaced_percentage_block_storage ==
680             kRareDataPercentage &&
681         rare_data_->replaced_percentage_resolution_block_size !=
682             other.rare_data_->replaced_percentage_resolution_block_size)
683       return false;
684 
685     return true;
686   }
687 
ReplaceTableConstraintSpaceData(const NGTableConstraintSpaceData & table_data)688   void ReplaceTableConstraintSpaceData(
689       const NGTableConstraintSpaceData& table_data) {
690     DCHECK(HasRareData());
691     rare_data_->ReplaceTableConstraintSpaceData(table_data);
692   }
693 
694   String ToString() const;
695 
696  private:
697   friend class NGConstraintSpaceBuilder;
698 
699   // This struct defines all of the inputs to layout which we consider rare.
700   // Primarily this is:
701   //  - Percentage resolution sizes which differ from the available size or
702   //    aren't indefinite.
703   //  - The margin strut.
704   //  - Anything to do with floats (the exclusion space, clearance offset, etc).
705   //  - Anything to do with fragmentation.
706   //  - Anything to do with stretching of math operators.
707   //
708   // This information is kept in a separate in this heap-allocated struct to
709   // reduce memory usage. Over time this may have to change based on usage data.
710   struct RareData {
711     USING_FAST_MALLOC(RareData);
712 
713    public:
714     // |RareData| unions different types of data which are mutually exclusive.
715     // They fall into the following categories:
716     enum DataUnionType {
717       kNone,
718       kBlockData,         // An inflow block which doesn't establish a new FC.
719       kTableCellData,     // A table-cell (display: table-cell).
720       kTableRowData,      // A table-row (display: table-row).
721       kTableSectionData,  // A table-section (display: table-section).
722       kCustomData,        // A custom layout (display: layout(foo)).
723       kStretchData        // The target inline/block stretch sizes for MathML.
724     };
725 
RareDataRareData726     explicit RareData(const NGBfcOffset bfc_offset)
727         : bfc_offset(bfc_offset),
728           data_union_type(static_cast<unsigned>(kNone)),
729           is_restricted_block_size_table_cell(false),
730           hide_table_cell_if_empty(false),
731           block_direction_fragmentation_type(
732               static_cast<unsigned>(kFragmentNone)),
733           is_inside_balanced_columns(false),
734           is_in_column_bfc(false),
735           early_break_appeal(kBreakAppealLastResort) {}
RareDataRareData736     RareData(const RareData& other)
737         : percentage_resolution_size(other.percentage_resolution_size),
738           replaced_percentage_resolution_block_size(
739               other.replaced_percentage_resolution_block_size),
740           block_start_annotation_space(other.block_start_annotation_space),
741           bfc_offset(other.bfc_offset),
742           fragmentainer_block_size(other.fragmentainer_block_size),
743           fragmentainer_offset_at_bfc(other.fragmentainer_offset_at_bfc),
744           data_union_type(other.data_union_type),
745           is_restricted_block_size_table_cell(
746               other.is_restricted_block_size_table_cell),
747           hide_table_cell_if_empty(other.hide_table_cell_if_empty),
748           block_direction_fragmentation_type(
749               other.block_direction_fragmentation_type),
750           is_inside_balanced_columns(other.is_inside_balanced_columns),
751           is_in_column_bfc(other.is_in_column_bfc),
752           early_break_appeal(other.early_break_appeal) {
753       switch (data_union_type) {
754         case kNone:
755           break;
756         case kBlockData:
757           new (&block_data_) BlockData(other.block_data_);
758           break;
759         case kTableCellData:
760           new (&table_cell_data_) TableCellData(other.table_cell_data_);
761           break;
762         case kTableRowData:
763           new (&table_row_data_) TableRowData(other.table_row_data_);
764           break;
765         case kTableSectionData:
766           new (&table_section_data_)
767               TableSectionData(other.table_section_data_);
768           break;
769         case kCustomData:
770           new (&custom_data_) CustomData(other.custom_data_);
771           break;
772         case kStretchData:
773           new (&stretch_data_) StretchData(other.stretch_data_);
774           break;
775         default:
776           NOTREACHED();
777       }
778     }
~RareDataRareData779     ~RareData() {
780       switch (data_union_type) {
781         case kNone:
782           break;
783         case kBlockData:
784           block_data_.~BlockData();
785           break;
786         case kTableCellData:
787           table_cell_data_.~TableCellData();
788           break;
789         case kTableRowData:
790           table_row_data_.~TableRowData();
791           break;
792         case kTableSectionData:
793           table_section_data_.~TableSectionData();
794           break;
795         case kCustomData:
796           custom_data_.~CustomData();
797           break;
798         case kStretchData:
799           stretch_data_.~StretchData();
800           break;
801         default:
802           NOTREACHED();
803       }
804     }
805 
MaySkipLayoutRareData806     bool MaySkipLayout(const RareData& other) const {
807       if (fragmentainer_block_size != other.fragmentainer_block_size ||
808           fragmentainer_offset_at_bfc != other.fragmentainer_offset_at_bfc ||
809           data_union_type != other.data_union_type ||
810           is_restricted_block_size_table_cell !=
811               other.is_restricted_block_size_table_cell ||
812           hide_table_cell_if_empty != other.hide_table_cell_if_empty ||
813           block_direction_fragmentation_type !=
814               other.block_direction_fragmentation_type ||
815           is_inside_balanced_columns != other.is_inside_balanced_columns ||
816           is_in_column_bfc != other.is_in_column_bfc ||
817           early_break_appeal != other.early_break_appeal)
818         return false;
819 
820       switch (data_union_type) {
821         case kNone:
822           return true;
823         case kBlockData:
824           return block_data_.MaySkipLayout(other.block_data_);
825         case kTableCellData:
826           return table_cell_data_.MaySkipLayout(other.table_cell_data_);
827         case kTableRowData:
828           return table_row_data_.MaySkipLayout(other.table_row_data_);
829         case kTableSectionData:
830           return table_section_data_.MaySkipLayout(other.table_section_data_);
831         case kCustomData:
832           return custom_data_.MaySkipLayout(other.custom_data_);
833         case kStretchData:
834           return stretch_data_.MaySkipLayout(other.stretch_data_);
835       }
836       NOTREACHED();
837       return false;
838     }
839 
840     // Must be kept in sync with members checked within |MaySkipLayout|.
IsInitialForMaySkipLayoutRareData841     bool IsInitialForMaySkipLayout() const {
842       if (fragmentainer_block_size != kIndefiniteSize ||
843           fragmentainer_offset_at_bfc || is_restricted_block_size_table_cell ||
844           hide_table_cell_if_empty ||
845           block_direction_fragmentation_type != kFragmentNone ||
846           is_inside_balanced_columns || is_in_column_bfc ||
847           early_break_appeal != kBreakAppealLastResort)
848         return false;
849 
850       switch (data_union_type) {
851         case kNone:
852           return true;
853         case kBlockData:
854           return block_data_.IsInitialForMaySkipLayout();
855         case kTableCellData:
856           return table_cell_data_.IsInitialForMaySkipLayout();
857         case kTableRowData:
858           return table_row_data_.IsInitialForMaySkipLayout();
859         case kTableSectionData:
860           return table_section_data_.IsInitialForMaySkipLayout();
861         case kCustomData:
862           return custom_data_.IsInitialForMaySkipLayout();
863         case kStretchData:
864           return stretch_data_.IsInitialForMaySkipLayout();
865       }
866       NOTREACHED();
867       return false;
868     }
869 
BlockStartAnnotationSpaceRareData870     LayoutUnit BlockStartAnnotationSpace() const {
871       return block_start_annotation_space;
872     }
873 
SetBlockStartAnnotationSpaceRareData874     void SetBlockStartAnnotationSpace(LayoutUnit space) {
875       block_start_annotation_space = space;
876     }
877 
MarginStrutRareData878     NGMarginStrut MarginStrut() const {
879       return data_union_type == kBlockData ? block_data_.margin_strut
880                                            : NGMarginStrut();
881     }
882 
SetMarginStrutRareData883     void SetMarginStrut(const NGMarginStrut& margin_strut) {
884       EnsureBlockData()->margin_strut = margin_strut;
885     }
886 
OptimisticBfcBlockOffsetRareData887     base::Optional<LayoutUnit> OptimisticBfcBlockOffset() const {
888       return data_union_type == kBlockData
889                  ? block_data_.optimistic_bfc_block_offset
890                  : base::nullopt;
891     }
892 
SetOptimisticBfcBlockOffsetRareData893     void SetOptimisticBfcBlockOffset(LayoutUnit optimistic_bfc_block_offset) {
894       EnsureBlockData()->optimistic_bfc_block_offset =
895           optimistic_bfc_block_offset;
896     }
897 
ForcedBfcBlockOffsetRareData898     base::Optional<LayoutUnit> ForcedBfcBlockOffset() const {
899       return data_union_type == kBlockData ? block_data_.forced_bfc_block_offset
900                                            : base::nullopt;
901     }
902 
SetForcedBfcBlockOffsetRareData903     void SetForcedBfcBlockOffset(LayoutUnit forced_bfc_block_offset) {
904       EnsureBlockData()->forced_bfc_block_offset = forced_bfc_block_offset;
905     }
906 
ClearanceOffsetRareData907     LayoutUnit ClearanceOffset() const {
908       return data_union_type == kBlockData ? block_data_.clearance_offset
909                                            : LayoutUnit::Min();
910     }
911 
SetClearanceOffsetRareData912     void SetClearanceOffset(LayoutUnit clearance_offset) {
913       EnsureBlockData()->clearance_offset = clearance_offset;
914     }
915 
LinesUntilClampRareData916     base::Optional<int> LinesUntilClamp() const {
917       return data_union_type == kBlockData ? block_data_.lines_until_clamp
918                                            : base::nullopt;
919     }
920 
SetLinesUntilClampRareData921     void SetLinesUntilClamp(int value) {
922       EnsureBlockData()->lines_until_clamp = value;
923     }
924 
TableCellBordersRareData925     NGBoxStrut TableCellBorders() const {
926       return data_union_type == kTableCellData
927                  ? table_cell_data_.table_cell_borders
928                  : NGBoxStrut();
929     }
930 
SetTableCellBordersRareData931     void SetTableCellBorders(const NGBoxStrut& table_cell_borders) {
932       EnsureTableCellData()->table_cell_borders = table_cell_borders;
933     }
934 
TableCellIntrinsicPaddingRareData935     NGBoxStrut TableCellIntrinsicPadding() const {
936       return data_union_type == kTableCellData
937                  ? NGBoxStrut(
938                        LayoutUnit(), LayoutUnit(),
939                        table_cell_data_
940                            .table_cell_intrinsic_padding_block_start,
941                        table_cell_data_.table_cell_intrinsic_padding_block_end)
942                  : NGBoxStrut();
943     }
944 
SetTableCellIntrinsicPaddingRareData945     void SetTableCellIntrinsicPadding(
946         const NGBoxStrut& table_cell_intrinsic_padding) {
947       EnsureTableCellData()->table_cell_intrinsic_padding_block_start =
948           table_cell_intrinsic_padding.block_start;
949       EnsureTableCellData()->table_cell_intrinsic_padding_block_end =
950           table_cell_intrinsic_padding.block_end;
951     }
952 
TableCellColumnIndexRareData953     wtf_size_t TableCellColumnIndex() const {
954       return data_union_type == kTableCellData
955                  ? table_cell_data_.table_cell_column_index
956                  : 0;
957     }
958 
SetTableCellColumnIndexRareData959     void SetTableCellColumnIndex(wtf_size_t table_cell_column_index) {
960       EnsureTableCellData()->table_cell_column_index = table_cell_column_index;
961     }
962 
TableCellAlignmentBaselineRareData963     base::Optional<LayoutUnit> TableCellAlignmentBaseline() const {
964       return data_union_type == kTableCellData
965                  ? table_cell_data_.table_cell_alignment_baseline
966                  : base::nullopt;
967     }
968 
SetTableCellAlignmentBaselineRareData969     void SetTableCellAlignmentBaseline(
970         LayoutUnit table_cell_alignment_baseline) {
971       EnsureTableCellData()->table_cell_alignment_baseline =
972           table_cell_alignment_baseline;
973     }
974 
IsTableCellHiddenForPaintRareData975     bool IsTableCellHiddenForPaint() const {
976       return data_union_type == kTableCellData &&
977              table_cell_data_.is_hidden_for_paint;
978     }
979 
SetIsTableCellHiddenForPaintRareData980     void SetIsTableCellHiddenForPaint(bool is_hidden_for_paint) {
981       EnsureTableCellData()->is_hidden_for_paint = is_hidden_for_paint;
982     }
983 
IsTableCellWithCollapsedBordersRareData984     bool IsTableCellWithCollapsedBorders() const {
985       return data_union_type == kTableCellData &&
986              table_cell_data_.has_collapsed_borders;
987     }
988 
SetIsTableCellWithCollapsedBordersRareData989     void SetIsTableCellWithCollapsedBorders(bool has_collapsed_borders) {
990       EnsureTableCellData()->has_collapsed_borders = has_collapsed_borders;
991     }
992 
SetTableRowDataRareData993     void SetTableRowData(
994         scoped_refptr<const NGTableConstraintSpaceData> table_data,
995         wtf_size_t row_index) {
996       EnsureTableRowData()->table_data = std::move(table_data);
997       EnsureTableRowData()->row_index = row_index;
998     }
999 
SetTableSectionDataRareData1000     void SetTableSectionData(
1001         scoped_refptr<const NGTableConstraintSpaceData> table_data,
1002         wtf_size_t section_index) {
1003       EnsureTableSectionData()->table_data = std::move(table_data);
1004       EnsureTableSectionData()->section_index = section_index;
1005     }
1006 
ReplaceTableConstraintSpaceDataRareData1007     void ReplaceTableConstraintSpaceData(
1008         const NGTableConstraintSpaceData& table_data) {
1009       DCHECK_EQ(data_union_type, kTableRowData);
1010       DCHECK(table_data.IsTableSpecificDataEqual(
1011           *(EnsureTableRowData()->table_data)));
1012       EnsureTableRowData()->table_data = &table_data;
1013     }
1014 
TableDataRareData1015     const NGTableConstraintSpaceData* TableData() {
1016       if (data_union_type == kTableRowData)
1017         return EnsureTableRowData()->table_data.get();
1018       if (data_union_type == kTableSectionData)
1019         return EnsureTableSectionData()->table_data.get();
1020       return nullptr;
1021     }
1022 
TableRowIndexRareData1023     wtf_size_t TableRowIndex() {
1024       return data_union_type == kTableRowData ? EnsureTableRowData()->row_index
1025                                               : kNotFound;
1026     }
1027 
TableSectionIndexRareData1028     wtf_size_t TableSectionIndex() {
1029       return data_union_type == kTableSectionData
1030                  ? EnsureTableSectionData()->section_index
1031                  : kNotFound;
1032     }
1033 
CustomLayoutDataRareData1034     SerializedScriptValue* CustomLayoutData() const {
1035       return data_union_type == kCustomData ? custom_data_.data.get() : nullptr;
1036     }
1037 
SetCustomLayoutDataRareData1038     void SetCustomLayoutData(
1039         scoped_refptr<SerializedScriptValue> custom_layout_data) {
1040       EnsureCustomData()->data = std::move(custom_layout_data);
1041     }
1042 
TargetStretchInlineSizeRareData1043     LayoutUnit TargetStretchInlineSize() const {
1044       return data_union_type == kStretchData
1045                  ? stretch_data_.target_stretch_inline_size
1046                  : kIndefiniteSize;
1047     }
1048 
SetTargetStretchInlineSizeRareData1049     void SetTargetStretchInlineSize(LayoutUnit target_stretch_inline_size) {
1050       EnsureStretchData()->target_stretch_inline_size =
1051           target_stretch_inline_size;
1052     }
1053 
TargetStretchAscentSizeRareData1054     LayoutUnit TargetStretchAscentSize() const {
1055       return data_union_type == kStretchData
1056                  ? stretch_data_.target_stretch_ascent_size
1057                  : kIndefiniteSize;
1058     }
1059 
SetTargetStretchAscentSizeRareData1060     void SetTargetStretchAscentSize(LayoutUnit target_stretch_ascent_size) {
1061       EnsureStretchData()->target_stretch_ascent_size =
1062           target_stretch_ascent_size;
1063     }
1064 
TargetStretchDescentSizeRareData1065     LayoutUnit TargetStretchDescentSize() const {
1066       return data_union_type == kStretchData
1067                  ? stretch_data_.target_stretch_descent_size
1068                  : kIndefiniteSize;
1069     }
1070 
SetTargetStretchDescentSizeRareData1071     void SetTargetStretchDescentSize(LayoutUnit target_stretch_descent_size) {
1072       EnsureStretchData()->target_stretch_descent_size =
1073           target_stretch_descent_size;
1074     }
1075 
1076     LogicalSize percentage_resolution_size;
1077     LayoutUnit replaced_percentage_resolution_block_size;
1078     LayoutUnit block_start_annotation_space;
1079     NGBfcOffset bfc_offset;
1080 
1081     LayoutUnit fragmentainer_block_size = kIndefiniteSize;
1082     LayoutUnit fragmentainer_offset_at_bfc;
1083 
1084     unsigned data_union_type : 3;
1085 
1086     unsigned is_restricted_block_size_table_cell : 1;
1087     unsigned hide_table_cell_if_empty : 1;
1088 
1089     unsigned block_direction_fragmentation_type : 2;
1090     unsigned is_inside_balanced_columns : 1;
1091     unsigned is_in_column_bfc : 1;
1092     unsigned early_break_appeal : 2;  // NGBreakAppeal
1093    private:
1094     struct BlockData {
MaySkipLayoutRareData::BlockData1095       bool MaySkipLayout(const BlockData& other) const {
1096         return lines_until_clamp == other.lines_until_clamp;
1097       }
1098 
IsInitialForMaySkipLayoutRareData::BlockData1099       bool IsInitialForMaySkipLayout() const {
1100         return !lines_until_clamp.has_value();
1101       }
1102 
1103       NGMarginStrut margin_strut;
1104       base::Optional<LayoutUnit> optimistic_bfc_block_offset;
1105       base::Optional<LayoutUnit> forced_bfc_block_offset;
1106       LayoutUnit clearance_offset = LayoutUnit::Min();
1107       base::Optional<int> lines_until_clamp;
1108     };
1109 
1110     struct TableCellData {
MaySkipLayoutRareData::TableCellData1111       bool MaySkipLayout(const TableCellData& other) const {
1112         // NOTE: We don't compare |table_cell_alignment_baseline| as it is
1113         // still possible to hit the cache if this differs.
1114         return table_cell_borders == other.table_cell_borders &&
1115                table_cell_intrinsic_padding_block_start ==
1116                    other.table_cell_intrinsic_padding_block_start &&
1117                table_cell_intrinsic_padding_block_end ==
1118                    other.table_cell_intrinsic_padding_block_end &&
1119                table_cell_column_index == other.table_cell_column_index &&
1120                is_hidden_for_paint == other.is_hidden_for_paint &&
1121                has_collapsed_borders == other.has_collapsed_borders;
1122       }
1123 
IsInitialForMaySkipLayoutRareData::TableCellData1124       bool IsInitialForMaySkipLayout() const {
1125         return table_cell_borders == NGBoxStrut() &&
1126                table_cell_intrinsic_padding_block_start == LayoutUnit() &&
1127                table_cell_intrinsic_padding_block_end == LayoutUnit() &&
1128                table_cell_column_index == kNotFound && !is_hidden_for_paint &&
1129                !has_collapsed_borders;
1130       }
1131 
1132       NGBoxStrut table_cell_borders;
1133       LayoutUnit table_cell_intrinsic_padding_block_start;
1134       LayoutUnit table_cell_intrinsic_padding_block_end;
1135       wtf_size_t table_cell_column_index = kNotFound;
1136       base::Optional<LayoutUnit> table_cell_alignment_baseline;
1137       bool is_hidden_for_paint = false;
1138       bool has_collapsed_borders = false;
1139     };
1140 
1141     struct TableRowData {
MaySkipLayoutRareData::TableRowData1142       bool MaySkipLayout(const TableRowData& other) const {
1143         return table_data->IsTableSpecificDataEqual(*other.table_data) &&
1144                table_data->MaySkipRowLayout(*other.table_data, row_index);
1145       }
IsInitialForMaySkipLayoutRareData::TableRowData1146       bool IsInitialForMaySkipLayout() const {
1147         return !table_data && row_index == kNotFound;
1148       }
1149 
1150       scoped_refptr<const NGTableConstraintSpaceData> table_data;
1151       wtf_size_t row_index = kNotFound;
1152     };
1153 
1154     struct TableSectionData {
MaySkipLayoutRareData::TableSectionData1155       bool MaySkipLayout(const TableSectionData& other) const {
1156         return table_data->IsTableSpecificDataEqual(*other.table_data) &&
1157                table_data->MaySkipSectionLayout(*other.table_data,
1158                                                 section_index);
1159       }
IsInitialForMaySkipLayoutRareData::TableSectionData1160       bool IsInitialForMaySkipLayout() const {
1161         return !table_data && section_index == kNotFound;
1162       }
1163 
1164       scoped_refptr<const NGTableConstraintSpaceData> table_data;
1165       wtf_size_t section_index = kNotFound;
1166     };
1167 
1168     struct CustomData {
1169       scoped_refptr<SerializedScriptValue> data;
1170 
MaySkipLayoutRareData::CustomData1171       bool MaySkipLayout(const CustomData& other) const {
1172         return data == other.data;
1173       }
1174 
IsInitialForMaySkipLayoutRareData::CustomData1175       bool IsInitialForMaySkipLayout() const { return !data; }
1176     };
1177 
1178     struct StretchData {
MaySkipLayoutRareData::StretchData1179       bool MaySkipLayout(const StretchData& other) const {
1180         return target_stretch_inline_size == other.target_stretch_inline_size &&
1181                target_stretch_ascent_size == other.target_stretch_ascent_size &&
1182                target_stretch_descent_size == other.target_stretch_descent_size;
1183       }
1184 
IsInitialForMaySkipLayoutRareData::StretchData1185       bool IsInitialForMaySkipLayout() const {
1186         return target_stretch_inline_size == kIndefiniteSize &&
1187                target_stretch_ascent_size == kIndefiniteSize &&
1188                target_stretch_descent_size == kIndefiniteSize;
1189       }
1190 
1191       LayoutUnit target_stretch_inline_size = kIndefiniteSize;
1192       LayoutUnit target_stretch_ascent_size = kIndefiniteSize;
1193       LayoutUnit target_stretch_descent_size = kIndefiniteSize;
1194     };
1195 
EnsureBlockDataRareData1196     BlockData* EnsureBlockData() {
1197       DCHECK(data_union_type == kNone || data_union_type == kBlockData);
1198       if (data_union_type != kBlockData) {
1199         data_union_type = kBlockData;
1200         new (&block_data_) BlockData();
1201       }
1202       return &block_data_;
1203     }
1204 
EnsureTableCellDataRareData1205     TableCellData* EnsureTableCellData() {
1206       DCHECK(data_union_type == kNone || data_union_type == kTableCellData);
1207       if (data_union_type != kTableCellData) {
1208         data_union_type = kTableCellData;
1209         new (&table_cell_data_) TableCellData();
1210       }
1211       return &table_cell_data_;
1212     }
1213 
EnsureTableRowDataRareData1214     TableRowData* EnsureTableRowData() {
1215       DCHECK(data_union_type == kNone || data_union_type == kTableRowData);
1216       if (data_union_type != kTableRowData) {
1217         data_union_type = kTableRowData;
1218         new (&table_row_data_) TableRowData();
1219       }
1220       return &table_row_data_;
1221     }
1222 
EnsureTableSectionDataRareData1223     TableSectionData* EnsureTableSectionData() {
1224       DCHECK(data_union_type == kNone || data_union_type == kTableSectionData);
1225       if (data_union_type != kTableSectionData) {
1226         data_union_type = kTableSectionData;
1227         new (&table_section_data_) TableSectionData();
1228       }
1229       return &table_section_data_;
1230     }
1231 
EnsureCustomDataRareData1232     CustomData* EnsureCustomData() {
1233       DCHECK(data_union_type == kNone || data_union_type == kCustomData);
1234       if (data_union_type != kCustomData) {
1235         data_union_type = kCustomData;
1236         new (&custom_data_) CustomData();
1237       }
1238       return &custom_data_;
1239     }
1240 
EnsureStretchDataRareData1241     StretchData* EnsureStretchData() {
1242       DCHECK(data_union_type == kNone || data_union_type == kStretchData);
1243       if (data_union_type != kStretchData) {
1244         data_union_type = kStretchData;
1245         new (&stretch_data_) StretchData();
1246       }
1247       return &stretch_data_;
1248     }
1249 
1250     union {
1251       BlockData block_data_;
1252       TableCellData table_cell_data_;
1253       TableRowData table_row_data_;
1254       TableSectionData table_section_data_;
1255       CustomData custom_data_;
1256       StretchData stretch_data_;
1257     };
1258   };
1259 
1260   // This struct simply allows us easily copy, compare, and initialize all the
1261   // bitfields without having to explicitly copy, compare, and initialize each
1262   // one (see the outer class constructors, and assignment operators).
1263   struct Bitfields {
1264     DISALLOW_NEW();
1265 
1266    public:
BitfieldsBitfields1267     Bitfields()
1268         : Bitfields({WritingMode::kHorizontalTb, TextDirection::kLtr}) {}
1269 
BitfieldsBitfields1270     explicit Bitfields(WritingDirectionMode writing_direction)
1271         : has_rare_data(false),
1272           adjoining_object_types(static_cast<unsigned>(kAdjoiningNone)),
1273           writing_mode(
1274               static_cast<unsigned>(writing_direction.GetWritingMode())),
1275           direction(static_cast<unsigned>(writing_direction.Direction())),
1276           is_table_cell(false),
1277           is_legacy_table_cell(false),
1278           is_anonymous(false),
1279           is_new_formatting_context(false),
1280           is_orthogonal_writing_mode_root(false),
1281           is_line_clamp_context(false),
1282           is_painted_atomically(false),
1283           use_first_line_style(false),
1284           ancestor_has_clearance_past_adjoining_floats(false),
1285           needs_baseline(false),
1286           baseline_algorithm_type(
1287               static_cast<unsigned>(NGBaselineAlgorithmType::kFirstLine)),
1288           cache_slot(static_cast<unsigned>(NGCacheSlot::kLayout)),
1289           is_shrink_to_fit(false),
1290           is_fixed_inline_size(false),
1291           is_fixed_block_size(false),
1292           is_fixed_block_size_indefinite(false),
1293           table_cell_child_layout_mode(static_cast<unsigned>(
1294               NGTableCellChildLayoutMode::kNotTableCellChild)),
1295           percentage_inline_storage(kSameAsAvailable),
1296           percentage_block_storage(kSameAsAvailable),
1297           replaced_percentage_block_storage(kSameAsAvailable) {}
1298 
MaySkipLayoutBitfields1299     bool MaySkipLayout(const Bitfields& other) const {
1300       return adjoining_object_types == other.adjoining_object_types &&
1301              writing_mode == other.writing_mode &&
1302              direction == other.direction &&
1303              is_table_cell == other.is_table_cell &&
1304              is_legacy_table_cell == other.is_legacy_table_cell &&
1305              is_anonymous == other.is_anonymous &&
1306              is_new_formatting_context == other.is_new_formatting_context &&
1307              is_orthogonal_writing_mode_root ==
1308                  other.is_orthogonal_writing_mode_root &&
1309              is_line_clamp_context == other.is_line_clamp_context &&
1310              is_painted_atomically == other.is_painted_atomically &&
1311              use_first_line_style == other.use_first_line_style &&
1312              ancestor_has_clearance_past_adjoining_floats ==
1313                  other.ancestor_has_clearance_past_adjoining_floats &&
1314              needs_baseline == other.needs_baseline &&
1315              baseline_algorithm_type == other.baseline_algorithm_type;
1316     }
1317 
AreSizeConstraintsEqualBitfields1318     bool AreSizeConstraintsEqual(const Bitfields& other) const {
1319       return is_shrink_to_fit == other.is_shrink_to_fit &&
1320              is_fixed_inline_size == other.is_fixed_inline_size &&
1321              is_fixed_block_size == other.is_fixed_block_size &&
1322              is_fixed_block_size_indefinite ==
1323                  other.is_fixed_block_size_indefinite &&
1324              table_cell_child_layout_mode == other.table_cell_child_layout_mode;
1325     }
1326 
1327     unsigned has_rare_data : 1;
1328     unsigned adjoining_object_types : 3;  // NGAdjoiningObjectTypes
1329     unsigned writing_mode : 3;
1330     unsigned direction : 1;
1331 
1332     unsigned is_table_cell : 1;
1333     unsigned is_legacy_table_cell : 1;
1334 
1335     unsigned is_anonymous : 1;
1336     unsigned is_new_formatting_context : 1;
1337     unsigned is_orthogonal_writing_mode_root : 1;
1338     unsigned is_line_clamp_context : 1;
1339 
1340     unsigned is_painted_atomically : 1;
1341     unsigned use_first_line_style : 1;
1342     unsigned ancestor_has_clearance_past_adjoining_floats : 1;
1343 
1344     unsigned needs_baseline : 1;
1345     unsigned baseline_algorithm_type : 1;
1346 
1347     unsigned cache_slot : 1;
1348 
1349     // Size constraints.
1350     unsigned is_shrink_to_fit : 1;
1351     unsigned is_fixed_inline_size : 1;
1352     unsigned is_fixed_block_size : 1;
1353     unsigned is_fixed_block_size_indefinite : 1;
1354     unsigned table_cell_child_layout_mode : 2;  // NGTableCellChildLayoutMode
1355 
1356     unsigned percentage_inline_storage : 2;           // NGPercentageStorage
1357     unsigned percentage_block_storage : 2;            // NGPercentageStorage
1358     unsigned replaced_percentage_block_storage : 2;   // NGPercentageStorage
1359   };
1360 
NGConstraintSpace(WritingDirectionMode writing_direction)1361   explicit NGConstraintSpace(WritingDirectionMode writing_direction)
1362       : bfc_offset_(), bitfields_(writing_direction) {}
1363 
HasRareData()1364   inline bool HasRareData() const { return bitfields_.has_rare_data; }
1365 
EnsureRareData()1366   RareData* EnsureRareData() {
1367     if (!HasRareData()) {
1368       rare_data_ = new RareData(bfc_offset_);
1369       bitfields_.has_rare_data = true;
1370     }
1371 
1372     return rare_data_;
1373   }
1374 
1375   LogicalSize available_size_;
1376 
1377   // To save a little space, we union these two fields. rare_data_ is valid if
1378   // the |has_rare_data| bit is set, otherwise bfc_offset_ is valid.
1379   union {
1380     NGBfcOffset bfc_offset_;
1381     RareData* rare_data_;
1382   };
1383 
1384   NGExclusionSpace exclusion_space_;
1385   Bitfields bitfields_;
1386 };
1387 
1388 inline std::ostream& operator<<(std::ostream& stream,
1389                                 const NGConstraintSpace& value) {
1390   return stream << value.ToString();
1391 }
1392 
1393 }  // namespace blink
1394 
1395 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_CONSTRAINT_SPACE_H_
1396