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_BOX_FRAGMENT_BUILDER_H_ 6 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_BOX_FRAGMENT_BUILDER_H_ 7 8 #include "third_party/blink/renderer/core/layout/geometry/box_sides.h" 9 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h" 10 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h" 11 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_fragment_geometry.h" 12 #include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h" 13 #include "third_party/blink/renderer/core/layout/ng/mathml/ng_mathml_paint_info.h" 14 #include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h" 15 #include "third_party/blink/renderer/core/layout/ng/ng_break_token.h" 16 #include "third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h" 17 #include "third_party/blink/renderer/core/layout/ng/ng_layout_overflow_calculator.h" 18 #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h" 19 #include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h" 20 #include "third_party/blink/renderer/core/layout/ng/table/ng_table_borders.h" 21 #include "third_party/blink/renderer/core/layout/ng/table/ng_table_fragment_data.h" 22 #include "third_party/blink/renderer/core/style/computed_style_constants.h" 23 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" 24 #include "third_party/blink/renderer/platform/wtf/hash_map.h" 25 26 namespace blink { 27 28 class NGPhysicalFragment; 29 30 class CORE_EXPORT NGBoxFragmentBuilder final 31 : public NGContainerFragmentBuilder { 32 DISALLOW_NEW(); 33 34 public: NGBoxFragmentBuilder(NGLayoutInputNode node,scoped_refptr<const ComputedStyle> style,const NGConstraintSpace * space,WritingDirectionMode writing_direction)35 NGBoxFragmentBuilder(NGLayoutInputNode node, 36 scoped_refptr<const ComputedStyle> style, 37 const NGConstraintSpace* space, 38 WritingDirectionMode writing_direction) 39 : NGContainerFragmentBuilder(node, 40 std::move(style), 41 space, 42 writing_direction), 43 box_type_(NGPhysicalFragment::NGBoxType::kNormalBox), 44 is_inline_formatting_context_(node.IsInline()) {} 45 46 // Build a fragment for LayoutObject without NGLayoutInputNode. LayoutInline 47 // has NGInlineItem but does not have corresponding NGLayoutInputNode. NGBoxFragmentBuilder(LayoutObject * layout_object,scoped_refptr<const ComputedStyle> style,WritingDirectionMode writing_direction)48 NGBoxFragmentBuilder(LayoutObject* layout_object, 49 scoped_refptr<const ComputedStyle> style, 50 WritingDirectionMode writing_direction) 51 : NGContainerFragmentBuilder(/* node */ nullptr, 52 std::move(style), 53 /* space */ nullptr, 54 writing_direction), 55 box_type_(NGPhysicalFragment::NGBoxType::kNormalBox), 56 is_inline_formatting_context_(true) { 57 layout_object_ = layout_object; 58 } 59 SetInitialFragmentGeometry(const NGFragmentGeometry & initial_fragment_geometry)60 void SetInitialFragmentGeometry( 61 const NGFragmentGeometry& initial_fragment_geometry) { 62 initial_fragment_geometry_ = &initial_fragment_geometry; 63 size_ = initial_fragment_geometry_->border_box_size; 64 is_initial_block_size_indefinite_ = size_.block_size == kIndefiniteSize; 65 66 border_padding_ = 67 initial_fragment_geometry.border + initial_fragment_geometry.padding; 68 border_scrollbar_padding_ = 69 border_padding_ + initial_fragment_geometry.scrollbar; 70 if (space_) { 71 child_available_size_ = CalculateChildAvailableSize( 72 *space_, To<NGBlockNode>(node_), size_, border_scrollbar_padding_); 73 } 74 } 75 AdjustBorderScrollbarPaddingForFragmentation(const NGBlockBreakToken * break_token)76 void AdjustBorderScrollbarPaddingForFragmentation( 77 const NGBlockBreakToken* break_token) { 78 if (LIKELY(!break_token)) 79 return; 80 if (break_token->IsBreakBefore()) 81 return; 82 border_scrollbar_padding_.block_start = LayoutUnit(); 83 } 84 AdjustBorderScrollbarPaddingForTableCell()85 void AdjustBorderScrollbarPaddingForTableCell() { 86 if (!space_->IsTableCell()) 87 return; 88 border_scrollbar_padding_ += 89 ComputeIntrinsicPadding(*space_, *style_, Scrollbar()); 90 } 91 InitialFragmentGeometry()92 const NGFragmentGeometry& InitialFragmentGeometry() const { 93 DCHECK(initial_fragment_geometry_); 94 return *initial_fragment_geometry_; 95 } 96 97 // Use the block-size setters/getters further down instead of the inherited 98 // ones. 99 LayoutUnit BlockSize() const = delete; 100 void SetBlockSize(LayoutUnit block_size) = delete; 101 102 // Set the total border-box block-size of all the fragments to be generated 103 // from this node (as if we stitched them together). Layout algorithms are 104 // expected to pass this value, and at the end of layout (if block 105 // fragmentation is needed), the fragmentation machinery will be invoked to 106 // adjust the block-size to the correct size, ensuring that we break at the 107 // best location. SetFragmentsTotalBlockSize(LayoutUnit block_size)108 void SetFragmentsTotalBlockSize(LayoutUnit block_size) { 109 #if DCHECK_IS_ON() 110 // Note that we just store the block-size in a shared field. We have a flag 111 // for debugging, to assert that we know what we're doing when attempting to 112 // access the data. 113 block_size_is_for_all_fragments_ = true; 114 #endif 115 size_.block_size = block_size; 116 } FragmentsTotalBlockSize()117 LayoutUnit FragmentsTotalBlockSize() const { 118 #if DCHECK_IS_ON() 119 if (has_block_fragmentation_) 120 DCHECK(block_size_is_for_all_fragments_); 121 #endif 122 return size_.block_size; 123 } 124 125 // Set the final block-size of this fragment. SetFragmentBlockSize(LayoutUnit block_size)126 void SetFragmentBlockSize(LayoutUnit block_size) { 127 #if DCHECK_IS_ON() 128 // Note that we just store the block-size in a shared field. We have a flag 129 // for debugging, to assert that we know what we're doing when attempting to 130 // access the data. 131 block_size_is_for_all_fragments_ = false; 132 #endif 133 size_.block_size = block_size; 134 } 135 FragmentBlockSize()136 LayoutUnit FragmentBlockSize() const { 137 #if DCHECK_IS_ON() 138 if (has_block_fragmentation_) 139 DCHECK(!block_size_is_for_all_fragments_); 140 #endif 141 return size_.block_size; 142 } 143 SetOverflowBlockSize(LayoutUnit overflow_block_size)144 void SetOverflowBlockSize(LayoutUnit overflow_block_size) { 145 overflow_block_size_ = overflow_block_size; 146 } SetIntrinsicBlockSize(LayoutUnit intrinsic_block_size)147 void SetIntrinsicBlockSize(LayoutUnit intrinsic_block_size) { 148 intrinsic_block_size_ = intrinsic_block_size; 149 } IntrinsicBlockSize()150 LayoutUnit IntrinsicBlockSize() const { return intrinsic_block_size_; } Borders()151 const NGBoxStrut& Borders() const { 152 DCHECK(initial_fragment_geometry_); 153 DCHECK_NE(BoxType(), NGPhysicalFragment::kInlineBox); 154 return initial_fragment_geometry_->border; 155 } Scrollbar()156 const NGBoxStrut& Scrollbar() const { 157 DCHECK(initial_fragment_geometry_); 158 return initial_fragment_geometry_->scrollbar; 159 } Padding()160 const NGBoxStrut& Padding() const { 161 DCHECK(initial_fragment_geometry_); 162 return initial_fragment_geometry_->padding; 163 } InitialBorderBoxSize()164 const LogicalSize& InitialBorderBoxSize() const { 165 DCHECK(initial_fragment_geometry_); 166 return initial_fragment_geometry_->border_box_size; 167 } BorderPadding()168 const NGBoxStrut& BorderPadding() const { 169 DCHECK(initial_fragment_geometry_); 170 return border_padding_; 171 } BorderScrollbarPadding()172 const NGBoxStrut& BorderScrollbarPadding() const { 173 DCHECK(initial_fragment_geometry_); 174 return border_scrollbar_padding_; 175 } 176 // The child available-size is subtly different from the content-box size of 177 // an element. For an anonymous-block the child available-size is equal to 178 // its non-anonymous parent (similar to percentages). ChildAvailableSize()179 const LogicalSize& ChildAvailableSize() const { 180 DCHECK(initial_fragment_geometry_); 181 DCHECK(space_); 182 return child_available_size_; 183 } Node()184 const NGBlockNode& Node() { 185 DCHECK(node_); 186 return To<NGBlockNode>(node_); 187 } 188 189 // Add a break token for a child that doesn't yet have any fragments, because 190 // its first fragment is to be produced in the next fragmentainer. This will 191 // add a break token for the child, but no fragment. Break appeal should 192 // always be provided for regular in-flow children. For other types of 193 // children it may be omitted, if the break shouldn't affect the appeal of 194 // breaking inside this container. 195 void AddBreakBeforeChild(NGLayoutInputNode child, 196 base::Optional<NGBreakAppeal> appeal, 197 bool is_forced_break); 198 199 // Add a layout result. This involves appending the fragment and its relative 200 // offset to the builder, but also keeping track of out-of-flow positioned 201 // descendants, propagating fragmentainer breaks, and more. 202 void AddResult(const NGLayoutResult&, const LogicalOffset); 203 AddChild(scoped_refptr<const NGPhysicalTextFragment> child,const LogicalOffset & offset)204 void AddChild(scoped_refptr<const NGPhysicalTextFragment> child, 205 const LogicalOffset& offset) { 206 AddChildInternal(child, offset); 207 } 208 209 void AddChild(const NGPhysicalContainerFragment&, 210 const LogicalOffset&, 211 const LayoutInline* inline_container = nullptr, 212 const NGMarginStrut* margin_strut = nullptr, 213 bool is_self_collapsing = false); 214 215 // Manually add a break token to the builder. Note that we're assuming that 216 // this break token is for content in the same flow as this parent. 217 void AddBreakToken(scoped_refptr<const NGBreakToken>, 218 bool is_in_parallel_flow = false); 219 220 void AddOutOfFlowLegacyCandidate(NGBlockNode, 221 const NGLogicalStaticPosition&, 222 const LayoutInline* inline_container); 223 224 // Specify whether this will be the first fragment generated for the node. SetIsFirstForNode(bool is_first)225 void SetIsFirstForNode(bool is_first) { is_first_for_node_ = is_first; } 226 227 // Set how much of the block-size we've used so far for this box. This will be 228 // the sum of the block-size of all previous fragments PLUS the one we're 229 // building now. SetConsumedBlockSize(LayoutUnit size)230 void SetConsumedBlockSize(LayoutUnit size) { consumed_block_size_ = size; } 231 232 // Set how much of the column block-size we've used so far. This will be used 233 // to determine the block-size of any new columns added by descendant 234 // out-of-flow positioned elements. SetBlockOffsetForAdditionalColumns(LayoutUnit size)235 void SetBlockOffsetForAdditionalColumns(LayoutUnit size) { 236 block_offset_for_additional_columns_ = size; 237 } BlockOffsetForAdditionalColumns()238 LayoutUnit BlockOffsetForAdditionalColumns() const { 239 return block_offset_for_additional_columns_; 240 } 241 SetSequenceNumber(unsigned sequence_number)242 void SetSequenceNumber(unsigned sequence_number) { 243 sequence_number_ = sequence_number; 244 } 245 246 // Return true if we broke inside this node on our own initiative (typically 247 // not because of a child break, but rather due to the size of this node). DidBreakSelf()248 bool DidBreakSelf() const { return did_break_self_; } SetDidBreakSelf()249 void SetDidBreakSelf() { did_break_self_ = true; } 250 251 // Store the previous break token, if one exists. SetPreviousBreakToken(scoped_refptr<const NGBlockBreakToken> break_token)252 void SetPreviousBreakToken( 253 scoped_refptr<const NGBlockBreakToken> break_token) { 254 previous_break_token_ = std::move(break_token); 255 } PreviousBreakToken()256 const NGBlockBreakToken* PreviousBreakToken() const { 257 return previous_break_token_.get(); 258 } 259 260 // Return true if we need to break before or inside any child, doesn't matter 261 // if it's in-flow or not. As long as there are only breaks in parallel flows, 262 // we may continue layout, but when we're done, we'll need to create a break 263 // token for this fragment nevertheless, so that we re-enter, descend and 264 // resume at the broken children in the next fragmentainer. HasChildBreakInside()265 bool HasChildBreakInside() const { 266 if (!child_break_tokens_.IsEmpty()) 267 return true; 268 // Inline nodes produce a "finished" trailing break token even if we don't 269 // need to block-fragment. 270 return !inline_break_tokens_.IsEmpty() && 271 !inline_break_tokens_.back()->IsFinished(); 272 } 273 274 // Return true if we need to break before or inside any in-flow child that 275 // doesn't establish a parallel flow. When this happens, we want to finish our 276 // fragment, create a break token, and resume in the next fragmentainer. HasInflowChildBreakInside()277 bool HasInflowChildBreakInside() const { 278 return has_inflow_child_break_inside_; 279 } 280 281 // Return true if we need to break before or inside any floated child. Floats 282 // are encapsulated by their container if the container establishes a new 283 // block formatting context. HasFloatBreakInside()284 bool HasFloatBreakInside() const { return has_float_break_inside_; } 285 286 // Report space shortage, i.e. how much more space would have been sufficient 287 // to prevent some piece of content from breaking. This information may be 288 // used by the column balancer to stretch columns. PropagateSpaceShortage(LayoutUnit space_shortage)289 void PropagateSpaceShortage(LayoutUnit space_shortage) { 290 DCHECK_GT(space_shortage, LayoutUnit()); 291 292 // Space shortage should only be reported when we already have a tentative 293 // fragmentainer block-size. It's meaningless to talk about space shortage 294 // in the initial column balancing pass, because then we have no 295 // fragmentainer block-size at all, so who's to tell what's too short or 296 // not? 297 DCHECK(!IsInitialColumnBalancingPass()); 298 299 if (minimal_space_shortage_ > space_shortage) 300 minimal_space_shortage_ = space_shortage; 301 } MinimalSpaceShortage()302 LayoutUnit MinimalSpaceShortage() const { return minimal_space_shortage_; } 303 PropagateTallestUnbreakableBlockSize(LayoutUnit unbreakable_block_size)304 void PropagateTallestUnbreakableBlockSize(LayoutUnit unbreakable_block_size) { 305 // We should only calculate the block-size of the tallest piece of 306 // unbreakable content during the initial column balancing pass, when we 307 // haven't set a tentative fragmentainer block-size yet. 308 DCHECK(IsInitialColumnBalancingPass()); 309 310 tallest_unbreakable_block_size_ = 311 std::max(tallest_unbreakable_block_size_, unbreakable_block_size); 312 } 313 SetIsInitialColumnBalancingPass()314 void SetIsInitialColumnBalancingPass() { 315 // Note that we have no dedicated flag for being in the initial column 316 // balancing pass here. We'll just bump tallest_unbreakable_block_size_ to 317 // 0, so that NGLayoutResult knows that we need to store unbreakable 318 // block-size. 319 DCHECK_EQ(tallest_unbreakable_block_size_, LayoutUnit::Min()); 320 tallest_unbreakable_block_size_ = LayoutUnit(); 321 } IsInitialColumnBalancingPass()322 bool IsInitialColumnBalancingPass() const { 323 return tallest_unbreakable_block_size_ >= LayoutUnit(); 324 } 325 SetInitialBreakBefore(EBreakBetween break_before)326 void SetInitialBreakBefore(EBreakBetween break_before) { 327 initial_break_before_ = break_before; 328 } 329 SetPreviousBreakAfter(EBreakBetween break_after)330 void SetPreviousBreakAfter(EBreakBetween break_after) { 331 previous_break_after_ = break_after; 332 } 333 334 // Set when this subtree has modified the incoming margin-strut, such that it 335 // may change our final position. SetSubtreeModifiedMarginStrut()336 void SetSubtreeModifiedMarginStrut() { 337 DCHECK(!BfcBlockOffset()); 338 subtree_modified_margin_strut_ = true; 339 } 340 341 // Join/"collapse" the previous (stored) break-after value with the next 342 // break-before value, to determine how to deal with breaking between two 343 // in-flow siblings. 344 EBreakBetween JoinedBreakBetweenValue(EBreakBetween break_before) const; 345 346 // Return the number of line boxes laid out. LineCount()347 int LineCount() const { return inline_break_tokens_.size(); } 348 349 // Set when we have iterated over all the children. This means that all 350 // children have been fully laid out, or have break tokens. No more children 351 // left to discover. SetHasSeenAllChildren()352 void SetHasSeenAllChildren() { has_seen_all_children_ = true; } HasSeenAllChildren()353 bool HasSeenAllChildren() { return has_seen_all_children_; } 354 SetIsAtBlockEnd()355 void SetIsAtBlockEnd() { is_at_block_end_ = true; } IsAtBlockEnd()356 bool IsAtBlockEnd() const { return is_at_block_end_; } 357 SetColumnSpanner(NGBlockNode spanner)358 void SetColumnSpanner(NGBlockNode spanner) { column_spanner_ = spanner; } FoundColumnSpanner()359 bool FoundColumnSpanner() const { return !!column_spanner_; } 360 SetLinesUntilClamp(const base::Optional<int> & value)361 void SetLinesUntilClamp(const base::Optional<int>& value) { 362 lines_until_clamp_ = value; 363 } 364 SetEarlyBreak(scoped_refptr<const NGEarlyBreak> breakpoint,NGBreakAppeal appeal)365 void SetEarlyBreak(scoped_refptr<const NGEarlyBreak> breakpoint, 366 NGBreakAppeal appeal) { 367 early_break_ = breakpoint; 368 break_appeal_ = appeal; 369 } HasEarlyBreak()370 bool HasEarlyBreak() const { return early_break_.get(); } EarlyBreak()371 const NGEarlyBreak& EarlyBreak() const { 372 DCHECK(early_break_.get()); 373 return *early_break_.get(); 374 } 375 376 // Set the highest break appeal found so far. This is either: 377 // 1: The highest appeal of a breakpoint found by our container 378 // 2: The appeal of a possible early break inside 379 // 3: The appeal of an actual break inside (to be stored in a break token) SetBreakAppeal(NGBreakAppeal appeal)380 void SetBreakAppeal(NGBreakAppeal appeal) { break_appeal_ = appeal; } BreakAppeal()381 NGBreakAppeal BreakAppeal() const { return break_appeal_; } 382 383 // Offsets are not supposed to be set during fragment construction, so we 384 // do not provide a setter here. 385 386 // Creates the fragment. Can only be called once. ToBoxFragment()387 scoped_refptr<const NGLayoutResult> ToBoxFragment() { 388 DCHECK_NE(BoxType(), NGPhysicalFragment::kInlineBox); 389 return ToBoxFragment(GetWritingMode()); 390 } ToInlineBoxFragment()391 scoped_refptr<const NGLayoutResult> ToInlineBoxFragment() { 392 // The logical coordinate for inline box uses line-relative writing-mode, 393 // not 394 // flow-relative. 395 DCHECK_EQ(BoxType(), NGPhysicalFragment::kInlineBox); 396 return ToBoxFragment(ToLineWritingMode(GetWritingMode())); 397 } 398 399 scoped_refptr<const NGLayoutResult> Abort(NGLayoutResult::EStatus); 400 401 NGPhysicalFragment::NGBoxType BoxType() const; SetBoxType(NGPhysicalFragment::NGBoxType box_type)402 void SetBoxType(NGPhysicalFragment::NGBoxType box_type) { 403 box_type_ = box_type; 404 } IsFragmentainerBoxType()405 bool IsFragmentainerBoxType() const { 406 return BoxType() == NGPhysicalFragment::kColumnBox; 407 } SetIsFieldsetContainer()408 void SetIsFieldsetContainer() { is_fieldset_container_ = true; } SetIsTableNGPart()409 void SetIsTableNGPart() { is_table_ng_part_ = true; } SetIsLegacyLayoutRoot()410 void SetIsLegacyLayoutRoot() { is_legacy_layout_root_ = true; } 411 SetIsInlineFormattingContext(bool is_inline_formatting_context)412 void SetIsInlineFormattingContext(bool is_inline_formatting_context) { 413 is_inline_formatting_context_ = is_inline_formatting_context; 414 } 415 SetIsMathMLFraction()416 void SetIsMathMLFraction() { is_math_fraction_ = true; } SetIsMathMLOperator()417 void SetIsMathMLOperator() { is_math_operator_ = true; } SetMathMLPaintInfo(UChar operator_character,scoped_refptr<const ShapeResultView> operator_shape_result_view,LayoutUnit operator_inline_size,LayoutUnit operator_ascent,LayoutUnit operator_descent)418 void SetMathMLPaintInfo( 419 UChar operator_character, 420 scoped_refptr<const ShapeResultView> operator_shape_result_view, 421 LayoutUnit operator_inline_size, 422 LayoutUnit operator_ascent, 423 LayoutUnit operator_descent) { 424 if (!mathml_paint_info_) 425 mathml_paint_info_ = std::make_unique<NGMathMLPaintInfo>(); 426 427 mathml_paint_info_->operator_character = operator_character; 428 mathml_paint_info_->operator_shape_result_view = 429 std::move(operator_shape_result_view); 430 431 mathml_paint_info_->operator_inline_size = operator_inline_size; 432 mathml_paint_info_->operator_ascent = operator_ascent; 433 mathml_paint_info_->operator_descent = operator_descent; 434 } SetMathMLPaintInfo(scoped_refptr<const ShapeResultView> operator_shape_result_view,LayoutUnit operator_inline_size,LayoutUnit operator_ascent,LayoutUnit operator_descent,LayoutUnit radical_operator_inline_offset,const NGBoxStrut & radical_base_margins)435 void SetMathMLPaintInfo( 436 scoped_refptr<const ShapeResultView> operator_shape_result_view, 437 LayoutUnit operator_inline_size, 438 LayoutUnit operator_ascent, 439 LayoutUnit operator_descent, 440 LayoutUnit radical_operator_inline_offset, 441 const NGBoxStrut& radical_base_margins) { 442 if (!mathml_paint_info_) 443 mathml_paint_info_ = std::make_unique<NGMathMLPaintInfo>(); 444 445 mathml_paint_info_->operator_character = kSquareRootCharacter; 446 mathml_paint_info_->operator_shape_result_view = 447 std::move(operator_shape_result_view); 448 449 mathml_paint_info_->operator_inline_size = operator_inline_size; 450 mathml_paint_info_->operator_ascent = operator_ascent; 451 mathml_paint_info_->operator_descent = operator_descent; 452 mathml_paint_info_->radical_base_margins = radical_base_margins; 453 mathml_paint_info_->radical_operator_inline_offset = 454 radical_operator_inline_offset; 455 } 456 SetSidesToInclude(LogicalBoxSides sides_to_include)457 void SetSidesToInclude(LogicalBoxSides sides_to_include) { 458 sides_to_include_ = sides_to_include; 459 } 460 461 // Either this function or SetBoxType must be called before ToBoxFragment(). SetIsNewFormattingContext(bool is_new_fc)462 void SetIsNewFormattingContext(bool is_new_fc) { is_new_fc_ = is_new_fc; } 463 SetCustomLayoutData(scoped_refptr<SerializedScriptValue> custom_layout_data)464 void SetCustomLayoutData( 465 scoped_refptr<SerializedScriptValue> custom_layout_data) { 466 custom_layout_data_ = std::move(custom_layout_data); 467 } 468 469 // Sets the alignment baseline for this fragment. SetBaseline(LayoutUnit baseline)470 void SetBaseline(LayoutUnit baseline) { baseline_ = baseline; } Baseline()471 base::Optional<LayoutUnit> Baseline() const { return baseline_; } 472 473 // Sets the last baseline for this fragment. SetLastBaseline(LayoutUnit baseline)474 void SetLastBaseline(LayoutUnit baseline) { 475 DCHECK_EQ(space_->BaselineAlgorithmType(), 476 NGBaselineAlgorithmType::kInlineBlock); 477 last_baseline_ = baseline; 478 } LastBaseline()479 base::Optional<LayoutUnit> LastBaseline() const { return last_baseline_; } 480 481 // The inline block baseline is at the block end margin edge under some 482 // circumstances. This function updates |LastBaseline| in such cases. 483 void SetLastBaselineToBlockEndMarginEdgeIfNeeded(); 484 SetTableGridRect(const PhysicalRect & table_grid_rect)485 void SetTableGridRect(const PhysicalRect& table_grid_rect) { 486 table_grid_rect_ = table_grid_rect; 487 } 488 SetTableColumnGeometry(const NGTableFragmentData::ColumnGeometries & table_column_geometries)489 void SetTableColumnGeometry( 490 const NGTableFragmentData::ColumnGeometries& table_column_geometries) { 491 table_column_geometries_ = table_column_geometries; 492 } 493 SetTableCollapsedBorders(const NGTableBorders & table_collapsed_borders)494 void SetTableCollapsedBorders(const NGTableBorders& table_collapsed_borders) { 495 table_collapsed_borders_ = &table_collapsed_borders; 496 } 497 SetTableCollapsedBordersGeometry(std::unique_ptr<NGTableFragmentData::CollapsedBordersGeometry> table_collapsed_borders_geometry)498 void SetTableCollapsedBordersGeometry( 499 std::unique_ptr<NGTableFragmentData::CollapsedBordersGeometry> 500 table_collapsed_borders_geometry) { 501 table_collapsed_borders_geometry_ = 502 std::move(table_collapsed_borders_geometry); 503 } 504 SetTableColumnCount(wtf_size_t table_column_count)505 void SetTableColumnCount(wtf_size_t table_column_count) { 506 table_column_count_ = table_column_count; 507 } 508 SetTableCellColumnIndex(wtf_size_t table_cell_column_index)509 void SetTableCellColumnIndex(wtf_size_t table_cell_column_index) { 510 table_cell_column_index_ = table_cell_column_index; 511 } 512 513 // The |NGFragmentItemsBuilder| for the inline formatting context of this box. ItemsBuilder()514 NGFragmentItemsBuilder* ItemsBuilder() { return items_builder_; } SetItemsBuilder(NGFragmentItemsBuilder * builder)515 void SetItemsBuilder(NGFragmentItemsBuilder* builder) { 516 items_builder_ = builder; 517 } 518 519 // Returns offset for given child. DCHECK if child not found. 520 // Warning: Do not call unless necessary. 521 LogicalOffset GetChildOffset(const LayoutObject* child) const; 522 523 // Inline containing block geometry is defined by two rectangles, generated 524 // by fragments of the LayoutInline. 525 struct InlineContainingBlockGeometry { 526 DISALLOW_NEW(); 527 // Union of fragments generated on the first line. 528 PhysicalRect start_fragment_union_rect; 529 // Union of fragments generated on the last line. 530 PhysicalRect end_fragment_union_rect; 531 }; 532 533 using InlineContainingBlockMap = 534 HashMap<const LayoutObject*, 535 base::Optional<InlineContainingBlockGeometry>>; 536 537 // Computes the geometry required for any inline containing blocks. 538 // |inline_containing_block_map| is a map whose keys specify which inline 539 // containing block geometry is required. 540 void ComputeInlineContainerGeometryFromFragmentTree( 541 InlineContainingBlockMap* inline_containing_block_map); 542 void ComputeInlineContainerGeometry( 543 InlineContainingBlockMap* inline_containing_block_map); 544 545 #if DCHECK_IS_ON() 546 // If we don't participate in a fragmentation context, this method can check 547 // that all block fragmentation related fields have their initial value. 548 void CheckNoBlockFragmentation() const; 549 #endif 550 551 // Moves all the children by |offset| in the block-direction. (Ensure that 552 // any baselines, OOFs, etc, are also moved by the appropriate amount). 553 void MoveChildrenInBlockDirection(LayoutUnit offset); 554 555 void SetMathItalicCorrection(LayoutUnit italic_correction); 556 557 private: 558 // Update whether we have fragmented in this flow. 559 void PropagateBreak(const NGLayoutResult&); 560 SetHasForcedBreak()561 void SetHasForcedBreak() { 562 has_forced_break_ = true; 563 minimal_space_shortage_ = LayoutUnit::Max(); 564 } 565 566 scoped_refptr<const NGLayoutResult> ToBoxFragment(WritingMode); 567 568 const NGFragmentGeometry* initial_fragment_geometry_ = nullptr; 569 NGBoxStrut border_padding_; 570 NGBoxStrut border_scrollbar_padding_; 571 LogicalSize child_available_size_; 572 LayoutUnit overflow_block_size_ = kIndefiniteSize; 573 LayoutUnit intrinsic_block_size_; 574 base::Optional<LogicalRect> inflow_bounds_; 575 576 NGFragmentItemsBuilder* items_builder_ = nullptr; 577 578 NGBlockNode column_spanner_ = nullptr; 579 580 NGPhysicalFragment::NGBoxType box_type_; 581 bool may_have_descendant_above_block_start_ = false; 582 bool is_fieldset_container_ = false; 583 bool is_table_ng_part_ = false; 584 bool is_initial_block_size_indefinite_ = false; 585 bool is_inline_formatting_context_; 586 bool is_first_for_node_ = true; 587 bool did_break_self_ = false; 588 bool has_inflow_child_break_inside_ = false; 589 bool has_float_break_inside_ = false; 590 bool has_forced_break_ = false; 591 bool is_new_fc_ = false; 592 bool subtree_modified_margin_strut_ = false; 593 bool has_seen_all_children_ = false; 594 bool is_math_fraction_ = false; 595 bool is_math_operator_ = false; 596 bool is_at_block_end_ = false; 597 LayoutUnit consumed_block_size_; 598 LayoutUnit block_offset_for_additional_columns_; 599 unsigned sequence_number_ = 0; 600 601 LayoutUnit minimal_space_shortage_ = LayoutUnit::Max(); 602 LayoutUnit tallest_unbreakable_block_size_ = LayoutUnit::Min(); 603 604 // The break-before value on the initial child we cannot honor. There's no 605 // valid class A break point before a first child, only *between* siblings. 606 EBreakBetween initial_break_before_ = EBreakBetween::kAuto; 607 608 // The break-after value of the previous in-flow sibling. 609 EBreakBetween previous_break_after_ = EBreakBetween::kAuto; 610 611 base::Optional<LayoutUnit> baseline_; 612 base::Optional<LayoutUnit> last_baseline_; 613 614 // Table specific types. 615 base::Optional<PhysicalRect> table_grid_rect_; 616 base::Optional<NGTableFragmentData::ColumnGeometries> 617 table_column_geometries_; 618 scoped_refptr<const NGTableBorders> table_collapsed_borders_; 619 std::unique_ptr<NGTableFragmentData::CollapsedBordersGeometry> 620 table_collapsed_borders_geometry_; 621 base::Optional<wtf_size_t> table_column_count_; 622 623 // Table cell specific types. 624 base::Optional<wtf_size_t> table_cell_column_index_; 625 626 LogicalBoxSides sides_to_include_; 627 628 scoped_refptr<SerializedScriptValue> custom_layout_data_; 629 base::Optional<int> lines_until_clamp_; 630 631 std::unique_ptr<NGMathMLPaintInfo> mathml_paint_info_; 632 base::Optional<NGLayoutResult::MathData> math_data_; 633 634 scoped_refptr<const NGBlockBreakToken> previous_break_token_; 635 636 #if DCHECK_IS_ON() 637 // Describes what size_.block_size represents; either the size of a single 638 // fragment (false), or the size of all fragments for a node (true). 639 bool block_size_is_for_all_fragments_ = false; 640 #endif 641 642 friend class NGBlockBreakToken; 643 friend class NGPhysicalBoxFragment; 644 friend class NGLayoutResult; 645 }; 646 647 } // namespace blink 648 649 #endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_BOX_FRAGMENT_BUILDER_H_ 650