OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/layout/ng/ng_block_layout_algorithm.h" | 5 #include "core/layout/ng/ng_block_layout_algorithm.h" |
6 | 6 |
7 #include "core/layout/ng/inline/ng_inline_node.h" | 7 #include "core/layout/ng/inline/ng_inline_node.h" |
8 #include "core/layout/ng/ng_absolute_utils.h" | 8 #include "core/layout/ng/ng_absolute_utils.h" |
9 #include "core/layout/ng/ng_block_child_iterator.h" | 9 #include "core/layout/ng/ng_block_child_iterator.h" |
10 #include "core/layout/ng/ng_box_fragment.h" | 10 #include "core/layout/ng/ng_box_fragment.h" |
11 #include "core/layout/ng/ng_constraint_space.h" | 11 #include "core/layout/ng/ng_constraint_space.h" |
12 #include "core/layout/ng/ng_constraint_space_builder.h" | 12 #include "core/layout/ng/ng_constraint_space_builder.h" |
13 #include "core/layout/ng/ng_floats_utils.h" | 13 #include "core/layout/ng/ng_floats_utils.h" |
14 #include "core/layout/ng/ng_fragment.h" | 14 #include "core/layout/ng/ng_fragment.h" |
15 #include "core/layout/ng/ng_fragment_builder.h" | 15 #include "core/layout/ng/ng_fragment_builder.h" |
16 #include "core/layout/ng/ng_layout_opportunity_iterator.h" | 16 #include "core/layout/ng/ng_layout_opportunity_iterator.h" |
17 #include "core/layout/ng/ng_length_utils.h" | 17 #include "core/layout/ng/ng_length_utils.h" |
18 #include "core/layout/ng/ng_out_of_flow_layout_part.h" | 18 #include "core/layout/ng/ng_out_of_flow_layout_part.h" |
19 #include "core/layout/ng/ng_space_utils.h" | 19 #include "core/layout/ng/ng_space_utils.h" |
20 #include "core/style/ComputedStyle.h" | 20 #include "core/style/ComputedStyle.h" |
21 #include "platform/LengthFunctions.h" | 21 #include "platform/LengthFunctions.h" |
22 #include "wtf/Optional.h" | 22 #include "wtf/Optional.h" |
23 | 23 |
24 namespace blink { | 24 namespace blink { |
25 namespace { | 25 namespace { |
26 | 26 |
| 27 // Adjusts {@code offset} to the clearance line. |
| 28 void AdjustToClearance(const WTF::Optional<LayoutUnit>& clearance_offset, |
| 29 NGLogicalOffset* offset) { |
| 30 DCHECK(offset); |
| 31 if (clearance_offset) { |
| 32 offset->block_offset = |
| 33 std::max(clearance_offset.value(), offset->block_offset); |
| 34 } |
| 35 } |
| 36 |
27 // Returns if a child may be affected by its clear property. I.e. it will | 37 // Returns if a child may be affected by its clear property. I.e. it will |
28 // actually clear a float. | 38 // actually clear a float. |
29 bool ClearanceMayAffectLayout( | 39 bool ClearanceMayAffectLayout( |
30 const NGConstraintSpace& space, | 40 const NGConstraintSpace& space, |
31 const Vector<RefPtr<NGFloatingObject>>& unpositioned_floats, | 41 const Vector<RefPtr<NGFloatingObject>>& unpositioned_floats, |
32 const ComputedStyle& child_style) { | 42 const ComputedStyle& child_style) { |
33 const NGExclusions& exclusions = *space.Exclusions(); | 43 const NGExclusions& exclusions = *space.Exclusions(); |
34 EClear clear = child_style.Clear(); | 44 EClear clear = child_style.Clear(); |
35 bool should_clear_left = (clear == EClear::kBoth || clear == EClear::kLeft); | 45 bool should_clear_left = (clear == EClear::kBoth || clear == EClear::kLeft); |
36 bool should_clear_right = (clear == EClear::kBoth || clear == EClear::kRight); | 46 bool should_clear_right = (clear == EClear::kBoth || clear == EClear::kRight); |
(...skipping 19 matching lines...) Expand all Loading... |
56 | 66 |
57 // Whether we've run out of space in this flow. If so, there will be no work | 67 // Whether we've run out of space in this flow. If so, there will be no work |
58 // left to do for this block in this fragmentainer. | 68 // left to do for this block in this fragmentainer. |
59 bool IsOutOfSpace(const NGConstraintSpace& space, LayoutUnit content_size) { | 69 bool IsOutOfSpace(const NGConstraintSpace& space, LayoutUnit content_size) { |
60 return space.HasBlockFragmentation() && | 70 return space.HasBlockFragmentation() && |
61 content_size >= space.FragmentainerSpaceAvailable(); | 71 content_size >= space.FragmentainerSpaceAvailable(); |
62 } | 72 } |
63 | 73 |
64 } // namespace | 74 } // namespace |
65 | 75 |
| 76 void MaybeUpdateFragmentBfcOffset(const NGConstraintSpace& space, |
| 77 const NGLogicalOffset& offset, |
| 78 NGFragmentBuilder* builder) { |
| 79 DCHECK(builder); |
| 80 if (!builder->BfcOffset()) { |
| 81 NGLogicalOffset mutable_offset(offset); |
| 82 AdjustToClearance(space.ClearanceOffset(), &mutable_offset); |
| 83 builder->SetBfcOffset(mutable_offset); |
| 84 } |
| 85 } |
| 86 |
66 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm(NGBlockNode* node, | 87 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm(NGBlockNode* node, |
67 NGConstraintSpace* space, | 88 NGConstraintSpace* space, |
68 NGBlockBreakToken* break_token) | 89 NGBlockBreakToken* break_token) |
69 : NGLayoutAlgorithm(node, space, break_token), | 90 : NGLayoutAlgorithm(node, space, break_token), |
70 builder_(NGPhysicalFragment::kFragmentBox, node), | 91 builder_(NGPhysicalFragment::kFragmentBox, node), |
71 space_builder_(constraint_space_) {} | 92 space_builder_(constraint_space_) {} |
72 | 93 |
73 Optional<MinMaxContentSize> NGBlockLayoutAlgorithm::ComputeMinMaxContentSize() | 94 Optional<MinMaxContentSize> NGBlockLayoutAlgorithm::ComputeMinMaxContentSize() |
74 const { | 95 const { |
75 MinMaxContentSize sizes; | 96 MinMaxContentSize sizes; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 LayoutUnit inline_offset = | 134 LayoutUnit inline_offset = |
114 border_and_padding_.inline_start + curr_child_margins_.inline_start; | 135 border_and_padding_.inline_start + curr_child_margins_.inline_start; |
115 LayoutUnit block_offset = content_size_; | 136 LayoutUnit block_offset = content_size_; |
116 if (known_fragment_offset) { | 137 if (known_fragment_offset) { |
117 block_offset = known_fragment_offset.value().block_offset - | 138 block_offset = known_fragment_offset.value().block_offset - |
118 builder_.BfcOffset().value().block_offset; | 139 builder_.BfcOffset().value().block_offset; |
119 } | 140 } |
120 return {inline_offset, block_offset}; | 141 return {inline_offset, block_offset}; |
121 } | 142 } |
122 | 143 |
123 void NGBlockLayoutAlgorithm::UpdateFragmentBfcOffset( | |
124 const NGLogicalOffset& offset) { | |
125 if (!builder_.BfcOffset()) { | |
126 NGLogicalOffset bfc_offset = offset; | |
127 if (ConstraintSpace().ClearanceOffset()) { | |
128 bfc_offset.block_offset = std::max( | |
129 ConstraintSpace().ClearanceOffset().value(), offset.block_offset); | |
130 } | |
131 builder_.SetBfcOffset(bfc_offset); | |
132 } | |
133 } | |
134 | |
135 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { | 144 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { |
136 WTF::Optional<MinMaxContentSize> min_max_size; | 145 WTF::Optional<MinMaxContentSize> min_max_size; |
137 if (NeedMinMaxContentSize(ConstraintSpace(), Style())) | 146 if (NeedMinMaxContentSize(ConstraintSpace(), Style())) |
138 min_max_size = ComputeMinMaxContentSize(); | 147 min_max_size = ComputeMinMaxContentSize(); |
139 | 148 |
140 border_and_padding_ = ComputeBorders(ConstraintSpace(), Style()) + | 149 border_and_padding_ = ComputeBorders(ConstraintSpace(), Style()) + |
141 ComputePadding(ConstraintSpace(), Style()); | 150 ComputePadding(ConstraintSpace(), Style()); |
142 | 151 |
143 // TODO(layout-ng): For quirks mode, should we pass blockSize instead of -1? | 152 // TODO(layout-ng): For quirks mode, should we pass blockSize instead of -1? |
144 NGLogicalSize size( | 153 NGLogicalSize size( |
(...skipping 27 matching lines...) Expand all Loading... |
172 content_size_ = BreakToken() ? LayoutUnit() : border_and_padding_.block_start; | 181 content_size_ = BreakToken() ? LayoutUnit() : border_and_padding_.block_start; |
173 | 182 |
174 curr_margin_strut_ = ConstraintSpace().MarginStrut(); | 183 curr_margin_strut_ = ConstraintSpace().MarginStrut(); |
175 curr_bfc_offset_ = ConstraintSpace().BfcOffset(); | 184 curr_bfc_offset_ = ConstraintSpace().BfcOffset(); |
176 | 185 |
177 // Margins collapsing: | 186 // Margins collapsing: |
178 // Do not collapse margins between parent and its child if there is | 187 // Do not collapse margins between parent and its child if there is |
179 // border/padding between them. | 188 // border/padding between them. |
180 if (border_and_padding_.block_start) { | 189 if (border_and_padding_.block_start) { |
181 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | 190 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
182 UpdateFragmentBfcOffset(curr_bfc_offset_); | 191 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, |
| 192 &builder_); |
183 curr_margin_strut_ = NGMarginStrut(); | 193 curr_margin_strut_ = NGMarginStrut(); |
184 } | 194 } |
185 | 195 |
186 // If a new formatting context hits the if branch above then the BFC offset is | 196 // If a new formatting context hits the if branch above then the BFC offset is |
187 // still {} as the margin strut from the constraint space must also be empty. | 197 // still {} as the margin strut from the constraint space must also be empty. |
188 if (ConstraintSpace().IsNewFormattingContext()) { | 198 if (ConstraintSpace().IsNewFormattingContext()) { |
189 UpdateFragmentBfcOffset(curr_bfc_offset_); | 199 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, |
| 200 &builder_); |
190 DCHECK_EQ(curr_margin_strut_, NGMarginStrut()); | 201 DCHECK_EQ(curr_margin_strut_, NGMarginStrut()); |
191 DCHECK_EQ(builder_.BfcOffset().value(), NGLogicalOffset()); | 202 DCHECK_EQ(builder_.BfcOffset().value(), NGLogicalOffset()); |
192 curr_bfc_offset_ = {}; | 203 curr_bfc_offset_ = {}; |
193 } | 204 } |
194 | 205 |
195 curr_bfc_offset_.block_offset += content_size_; | 206 curr_bfc_offset_.block_offset += content_size_; |
196 | 207 |
197 while (child) { | 208 while (child) { |
198 if (child->IsBlock()) { | 209 if (child->IsBlock()) { |
199 EPosition position = child->Style().GetPosition(); | 210 EPosition position = child->Style().GetPosition(); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 size.block_size = | 252 size.block_size = |
242 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); | 253 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); |
243 builder_.SetBlockSize(size.block_size); | 254 builder_.SetBlockSize(size.block_size); |
244 | 255 |
245 // Layout our absolute and fixed positioned children. | 256 // Layout our absolute and fixed positioned children. |
246 NGOutOfFlowLayoutPart(ConstraintSpace(), Style(), &builder_).Run(); | 257 NGOutOfFlowLayoutPart(ConstraintSpace(), Style(), &builder_).Run(); |
247 | 258 |
248 // Non-empty blocks always know their position in space: | 259 // Non-empty blocks always know their position in space: |
249 if (size.block_size) { | 260 if (size.block_size) { |
250 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | 261 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
251 UpdateFragmentBfcOffset(curr_bfc_offset_); | 262 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, |
| 263 &builder_); |
252 PositionPendingFloats(curr_bfc_offset_.block_offset, | 264 PositionPendingFloats(curr_bfc_offset_.block_offset, |
253 MutableConstraintSpace(), &builder_); | 265 MutableConstraintSpace(), &builder_); |
254 } | 266 } |
255 | 267 |
256 // Margins collapsing: | 268 // Margins collapsing: |
257 // Do not collapse margins between the last in-flow child and bottom margin | 269 // Do not collapse margins between the last in-flow child and bottom margin |
258 // of its parent if the parent has height != auto() | 270 // of its parent if the parent has height != auto() |
259 if (!Style().LogicalHeight().IsAuto()) { | 271 if (!Style().LogicalHeight().IsAuto()) { |
260 // TODO(glebl): handle minLogicalHeight, maxLogicalHeight. | 272 // TODO(glebl): handle minLogicalHeight, maxLogicalHeight. |
261 curr_margin_strut_ = NGMarginStrut(); | 273 curr_margin_strut_ = NGMarginStrut(); |
(...skipping 28 matching lines...) Expand all Loading... |
290 child->IsBlock() && !is_floating && | 302 child->IsBlock() && !is_floating && |
291 !IsNewFormattingContextForBlockLevelChild(Style(), *child) && | 303 !IsNewFormattingContextForBlockLevelChild(Style(), *child) && |
292 ClearanceMayAffectLayout(ConstraintSpace(), builder_.UnpositionedFloats(), | 304 ClearanceMayAffectLayout(ConstraintSpace(), builder_.UnpositionedFloats(), |
293 child->Style()); | 305 child->Style()); |
294 | 306 |
295 // Children which may clear a float need to force all the pending floats to | 307 // Children which may clear a float need to force all the pending floats to |
296 // be positioned before layout. This also resolves the fragment's bfc offset. | 308 // be positioned before layout. This also resolves the fragment's bfc offset. |
297 if (should_position_pending_floats) { | 309 if (should_position_pending_floats) { |
298 LayoutUnit origin_point_block_offset = | 310 LayoutUnit origin_point_block_offset = |
299 curr_bfc_offset_.block_offset + curr_margin_strut_.Sum(); | 311 curr_bfc_offset_.block_offset + curr_margin_strut_.Sum(); |
300 UpdateFragmentBfcOffset( | 312 MaybeUpdateFragmentBfcOffset( |
301 {curr_bfc_offset_.inline_offset, origin_point_block_offset}); | 313 ConstraintSpace(), |
| 314 {curr_bfc_offset_.inline_offset, origin_point_block_offset}, &builder_); |
302 PositionPendingFloats(origin_point_block_offset, MutableConstraintSpace(), | 315 PositionPendingFloats(origin_point_block_offset, MutableConstraintSpace(), |
303 &builder_); | 316 &builder_); |
304 } | 317 } |
305 | 318 |
306 bool is_inflow = child->IsInline() || !is_floating; | 319 bool is_inflow = child->IsInline() || !is_floating; |
307 | 320 |
308 // Only inflow children (e.g. not floats) are included in the child's margin | 321 // Only inflow children (e.g. not floats) are included in the child's margin |
309 // strut as they do not participate in margin collapsing. | 322 // strut as they do not participate in margin collapsing. |
310 if (is_inflow) { | 323 if (is_inflow) { |
311 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; | 324 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; |
(...skipping 12 matching lines...) Expand all Loading... |
324 bool should_collapse_margins = | 337 bool should_collapse_margins = |
325 child->IsInline() || | 338 child->IsInline() || |
326 (!is_floating && | 339 (!is_floating && |
327 IsNewFormattingContextForBlockLevelChild(Style(), *child)); | 340 IsNewFormattingContextForBlockLevelChild(Style(), *child)); |
328 | 341 |
329 // Inline children or children which establish a block formatting context | 342 // Inline children or children which establish a block formatting context |
330 // collapse margins and position themselves immediately as they need to know | 343 // collapse margins and position themselves immediately as they need to know |
331 // their BFC offset for fragmentation purposes. | 344 // their BFC offset for fragmentation purposes. |
332 if (should_collapse_margins) { | 345 if (should_collapse_margins) { |
333 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | 346 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
334 UpdateFragmentBfcOffset(curr_bfc_offset_); | 347 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, |
| 348 &builder_); |
335 PositionPendingFloats(curr_bfc_offset_.block_offset, | 349 PositionPendingFloats(curr_bfc_offset_.block_offset, |
336 MutableConstraintSpace(), &builder_); | 350 MutableConstraintSpace(), &builder_); |
337 curr_margin_strut_ = {}; | 351 curr_margin_strut_ = {}; |
338 } | 352 } |
339 } | 353 } |
340 | 354 |
341 void NGBlockLayoutAlgorithm::FinishChildLayout( | 355 void NGBlockLayoutAlgorithm::FinishChildLayout( |
342 NGLayoutInputNode* child, | 356 NGLayoutInputNode* child, |
343 NGConstraintSpace* child_space, | 357 NGConstraintSpace* child_space, |
344 RefPtr<NGLayoutResult> layout_result) { | 358 RefPtr<NGLayoutResult> layout_result) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 | 390 |
377 // Determine the fragment's position in the parent space either by using | 391 // Determine the fragment's position in the parent space either by using |
378 // content_size_ or known fragment's BFC offset. | 392 // content_size_ or known fragment's BFC offset. |
379 WTF::Optional<NGLogicalOffset> bfc_offset; | 393 WTF::Optional<NGLogicalOffset> bfc_offset; |
380 if (child_space->IsNewFormattingContext()) { | 394 if (child_space->IsNewFormattingContext()) { |
381 DCHECK(builder_.BfcOffset()); | 395 DCHECK(builder_.BfcOffset()); |
382 bfc_offset = curr_bfc_offset_; | 396 bfc_offset = curr_bfc_offset_; |
383 } else if (fragment.BfcOffset()) { | 397 } else if (fragment.BfcOffset()) { |
384 // Fragment that knows its offset can be used to set parent's BFC position. | 398 // Fragment that knows its offset can be used to set parent's BFC position. |
385 curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset; | 399 curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset; |
386 UpdateFragmentBfcOffset(curr_bfc_offset_); | 400 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, |
| 401 &builder_); |
387 PositionPendingFloats(curr_bfc_offset_.block_offset, | 402 PositionPendingFloats(curr_bfc_offset_.block_offset, |
388 MutableConstraintSpace(), &builder_); | 403 MutableConstraintSpace(), &builder_); |
389 bfc_offset = curr_bfc_offset_; | 404 bfc_offset = curr_bfc_offset_; |
390 } else if (builder_.BfcOffset()) { | 405 } else if (builder_.BfcOffset()) { |
391 // Fragment doesn't know its offset but we can still calculate its BFC | 406 // Fragment doesn't know its offset but we can still calculate its BFC |
392 // position because the parent fragment's BFC is known. | 407 // position because the parent fragment's BFC is known. |
393 // Example: | 408 // Example: |
394 // BFC Offset is known here because of the padding. | 409 // BFC Offset is known here because of the padding. |
395 // <div style="padding: 1px"> | 410 // <div style="padding: 1px"> |
396 // <div id="empty-div" style="margins: 1px"></div> | 411 // <div id="empty-div" style="margins: 1px"></div> |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
484 NGLayoutInputNode* child) { | 499 NGLayoutInputNode* child) { |
485 DCHECK(child); | 500 DCHECK(child); |
486 | 501 |
487 const ComputedStyle& child_style = child->Style(); | 502 const ComputedStyle& child_style = child->Style(); |
488 bool is_new_bfc = IsNewFormattingContextForBlockLevelChild(Style(), *child); | 503 bool is_new_bfc = IsNewFormattingContextForBlockLevelChild(Style(), *child); |
489 space_builder_.SetIsNewFormattingContext(is_new_bfc) | 504 space_builder_.SetIsNewFormattingContext(is_new_bfc) |
490 .SetBfcOffset(curr_bfc_offset_); | 505 .SetBfcOffset(curr_bfc_offset_); |
491 | 506 |
492 if (child->IsInline()) { | 507 if (child->IsInline()) { |
493 // TODO(kojii): Setup space_builder_ appropriately for inline child. | 508 // TODO(kojii): Setup space_builder_ appropriately for inline child. |
494 space_builder_.SetBfcOffset(curr_bfc_offset_); | 509 space_builder_.SetBfcOffset(curr_bfc_offset_) |
| 510 .SetClearanceOffset(ConstraintSpace().ClearanceOffset()); |
495 return space_builder_.ToConstraintSpace( | 511 return space_builder_.ToConstraintSpace( |
496 FromPlatformWritingMode(Style().GetWritingMode())); | 512 FromPlatformWritingMode(Style().GetWritingMode())); |
497 } | 513 } |
498 | 514 |
499 space_builder_ | 515 space_builder_ |
500 .SetClearanceOffset( | 516 .SetClearanceOffset( |
501 GetClearanceOffset(constraint_space_->Exclusions(), child_style)) | 517 GetClearanceOffset(constraint_space_->Exclusions(), child_style)) |
502 .SetIsShrinkToFit(ShouldShrinkToFit(Style(), child_style)) | 518 .SetIsShrinkToFit(ShouldShrinkToFit(Style(), child_style)) |
503 .SetTextDirection(child_style.Direction()); | 519 .SetTextDirection(child_style.Direction()); |
504 | 520 |
(...skipping 13 matching lines...) Expand all Loading... |
518 DCHECK(builder_.BfcOffset()); | 534 DCHECK(builder_.BfcOffset()); |
519 space_available -= curr_bfc_offset_.block_offset; | 535 space_available -= curr_bfc_offset_.block_offset; |
520 } | 536 } |
521 } | 537 } |
522 space_builder_.SetFragmentainerSpaceAvailable(space_available); | 538 space_builder_.SetFragmentainerSpaceAvailable(space_available); |
523 | 539 |
524 return space_builder_.ToConstraintSpace( | 540 return space_builder_.ToConstraintSpace( |
525 FromPlatformWritingMode(child_style.GetWritingMode())); | 541 FromPlatformWritingMode(child_style.GetWritingMode())); |
526 } | 542 } |
527 } // namespace blink | 543 } // namespace blink |
OLD | NEW |