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