Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(156)

Side by Side Diff: third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc

Issue 2899413002: [LayoutNG] Removes per-child state from NGBlockLayoutAlgorithm. (Closed)
Patch Set: rebase+testexpectations. Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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_constraint_space.h" 10 #include "core/layout/ng/ng_constraint_space.h"
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 60
61 // Whether we've run out of space in this flow. If so, there will be no work 61 // Whether we've run out of space in this flow. If so, there will be no work
62 // left to do for this block in this fragmentainer. 62 // left to do for this block in this fragmentainer.
63 bool IsOutOfSpace(const NGConstraintSpace& space, LayoutUnit content_size) { 63 bool IsOutOfSpace(const NGConstraintSpace& space, LayoutUnit content_size) {
64 return space.HasBlockFragmentation() && 64 return space.HasBlockFragmentation() &&
65 content_size >= space.FragmentainerSpaceAvailable(); 65 content_size >= space.FragmentainerSpaceAvailable();
66 } 66 }
67 67
68 } // namespace 68 } // namespace
69 69
70 // This struct is used for communicating to a child the position of the
71 // previous inflow child.
72 struct NGPreviousInflowPosition {
73 LayoutUnit bfc_block_offset;
74 LayoutUnit logical_block_offset;
75 NGMarginStrut margin_strut;
76 };
77
78 // This strut holds information for the current inflow child. The data is not
79 // useful outside of handling this single inflow child.
80 struct NGInflowChildData {
81 NGLogicalOffset bfc_offset_estimate;
82 NGMarginStrut margin_strut;
83 NGBoxStrut margins;
84 };
85
70 void MaybeUpdateFragmentBfcOffset(const NGConstraintSpace& space, 86 void MaybeUpdateFragmentBfcOffset(const NGConstraintSpace& space,
71 const NGLogicalOffset& offset, 87 LayoutUnit bfc_block_offset,
72 NGFragmentBuilder* builder) { 88 NGFragmentBuilder* builder) {
73 DCHECK(builder); 89 DCHECK(builder);
74 if (!builder->BfcOffset()) { 90 if (!builder->BfcOffset()) {
75 NGLogicalOffset mutable_offset(offset); 91 NGLogicalOffset bfc_offset = {space.BfcOffset().inline_offset,
76 AdjustToClearance(space.ClearanceOffset(), &mutable_offset); 92 bfc_block_offset};
77 builder->SetBfcOffset(mutable_offset); 93 AdjustToClearance(space.ClearanceOffset(), &bfc_offset);
94 builder->SetBfcOffset(bfc_offset);
78 } 95 }
79 } 96 }
80 97
81 void PositionPendingFloatsFromOffset(LayoutUnit origin_block_offset, 98 void PositionPendingFloatsFromOffset(LayoutUnit origin_block_offset,
82 LayoutUnit from_block_offset, 99 LayoutUnit from_block_offset,
83 NGFragmentBuilder* container_builder, 100 NGFragmentBuilder* container_builder,
84 NGConstraintSpace* space) { 101 NGConstraintSpace* space) {
85 DCHECK(container_builder->BfcOffset()) 102 DCHECK(container_builder->BfcOffset())
86 << "Parent BFC offset should be known here"; 103 << "Parent BFC offset should be known here";
87 const auto& unpositioned_floats = container_builder->UnpositionedFloats(); 104 const auto& unpositioned_floats = container_builder->UnpositionedFloats();
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 160
144 sizes.min_content = std::max(sizes.min_content, child_sizes.min_content); 161 sizes.min_content = std::max(sizes.min_content, child_sizes.min_content);
145 sizes.max_content = std::max(sizes.max_content, child_sizes.max_content); 162 sizes.max_content = std::max(sizes.max_content, child_sizes.max_content);
146 } 163 }
147 164
148 sizes.max_content = std::max(sizes.min_content, sizes.max_content); 165 sizes.max_content = std::max(sizes.min_content, sizes.max_content);
149 return sizes; 166 return sizes;
150 } 167 }
151 168
152 NGLogicalOffset NGBlockLayoutAlgorithm::CalculateLogicalOffset( 169 NGLogicalOffset NGBlockLayoutAlgorithm::CalculateLogicalOffset(
170 const NGBoxStrut& child_margins,
153 const WTF::Optional<NGLogicalOffset>& known_fragment_offset) { 171 const WTF::Optional<NGLogicalOffset>& known_fragment_offset) {
154 if (known_fragment_offset) 172 if (known_fragment_offset)
155 return known_fragment_offset.value() - ContainerBfcOffset(); 173 return known_fragment_offset.value() - ContainerBfcOffset();
156 LayoutUnit inline_offset = 174 LayoutUnit inline_offset =
157 border_and_padding_.inline_start + curr_child_margins_.inline_start; 175 border_and_padding_.inline_start + child_margins.inline_start;
176 // TODO(ikilpatrick): Using the content_size_ here looks suspicious - check.
158 return {inline_offset, content_size_}; 177 return {inline_offset, content_size_};
159 } 178 }
160 179
161 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { 180 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
162 WTF::Optional<MinMaxContentSize> min_max_size; 181 WTF::Optional<MinMaxContentSize> min_max_size;
163 if (NeedMinMaxContentSize(ConstraintSpace(), Style())) 182 if (NeedMinMaxContentSize(ConstraintSpace(), Style()))
164 min_max_size = ComputeMinMaxContentSize(); 183 min_max_size = ComputeMinMaxContentSize();
165 184
166 border_and_padding_ = ComputeBorders(ConstraintSpace(), Style()) + 185 border_and_padding_ = ComputeBorders(ConstraintSpace(), Style()) +
167 ComputePadding(ConstraintSpace(), Style()); 186 ComputePadding(ConstraintSpace(), Style());
(...skipping 24 matching lines...) Expand all
192 211
193 NGBlockChildIterator child_iterator(Node()->FirstChild(), BreakToken()); 212 NGBlockChildIterator child_iterator(Node()->FirstChild(), BreakToken());
194 NGBlockChildIterator::Entry entry = child_iterator.NextChild(); 213 NGBlockChildIterator::Entry entry = child_iterator.NextChild();
195 NGLayoutInputNode* child = entry.node; 214 NGLayoutInputNode* child = entry.node;
196 NGBreakToken* child_break_token = entry.token; 215 NGBreakToken* child_break_token = entry.token;
197 216
198 // If we are resuming from a break token our start border and padding is 217 // If we are resuming from a break token our start border and padding is
199 // within a previous fragment. 218 // within a previous fragment.
200 content_size_ = BreakToken() ? LayoutUnit() : border_and_padding_.block_start; 219 content_size_ = BreakToken() ? LayoutUnit() : border_and_padding_.block_start;
201 220
202 curr_margin_strut_ = ConstraintSpace().MarginStrut(); 221 NGMarginStrut input_margin_strut = ConstraintSpace().MarginStrut();
203 curr_bfc_offset_ = ConstraintSpace().BfcOffset(); 222 LayoutUnit input_bfc_block_offset =
223 ConstraintSpace().BfcOffset().block_offset;
204 224
205 // Margins collapsing: 225 // Margins collapsing:
206 // Do not collapse margins between parent and its child if there is 226 // Do not collapse margins between parent and its child if there is
207 // border/padding between them. 227 // border/padding between them.
208 if (border_and_padding_.block_start) { 228 if (border_and_padding_.block_start) {
209 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); 229 input_bfc_block_offset += input_margin_strut.Sum();
210 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, 230 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), input_bfc_block_offset,
211 &container_builder_); 231 &container_builder_);
212 curr_margin_strut_ = NGMarginStrut(); 232 // We reset the block offset here as it may have been effected by clearance.
233 input_bfc_block_offset = ContainerBfcOffset().block_offset;
234 input_margin_strut = NGMarginStrut();
213 } 235 }
214 236
215 // If a new formatting context hits the margin collapsing if-branch above 237 // If a new formatting context hits the margin collapsing if-branch above
216 // then the BFC offset is still {} as the margin strut from the constraint 238 // then the BFC offset is still {} as the margin strut from the constraint
217 // space must also be empty. 239 // space must also be empty.
218 // If we are resuming layout from a break token the same rule applies. Margin 240 // If we are resuming layout from a break token the same rule applies. Margin
219 // struts cannot pass through break tokens. 241 // struts cannot pass through break tokens.
220 if (ConstraintSpace().IsNewFormattingContext() || BreakToken()) { 242 if (ConstraintSpace().IsNewFormattingContext() || BreakToken()) {
221 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, 243 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), input_bfc_block_offset,
222 &container_builder_); 244 &container_builder_);
223 DCHECK_EQ(curr_margin_strut_, NGMarginStrut()); 245 DCHECK_EQ(input_margin_strut, NGMarginStrut());
224 DCHECK_EQ(container_builder_.BfcOffset().value(), NGLogicalOffset()); 246 DCHECK_EQ(container_builder_.BfcOffset().value(), NGLogicalOffset());
225 curr_bfc_offset_ = {};
226 } 247 }
227 248
228 curr_bfc_offset_.block_offset += content_size_; 249 input_bfc_block_offset += content_size_;
250
251 NGPreviousInflowPosition previous_inflow_position = {
252 input_bfc_block_offset, content_size_, input_margin_strut};
229 253
230 while (child) { 254 while (child) {
231 if (child->IsOutOfFlowPositioned()) { 255 if (child->IsOutOfFlowPositioned()) {
232 DCHECK(!child_break_token); 256 DCHECK(!child_break_token);
233 HandleOutOfFlowPositioned(ToNGBlockNode(child)); 257 HandleOutOfFlowPositioned(previous_inflow_position, ToNGBlockNode(child));
234 } else if (child->IsFloating()) { 258 } else if (child->IsFloating()) {
235 HandleFloating(ToNGBlockNode(child), 259 HandleFloating(previous_inflow_position, ToNGBlockNode(child),
236 ToNGBlockBreakToken(child_break_token)); 260 ToNGBlockBreakToken(child_break_token));
237 } else { 261 } else {
238 NGLogicalOffset child_bfc_offset = PrepareChildLayout(child); 262 NGInflowChildData child_data =
263 PrepareChildLayout(previous_inflow_position, child);
239 RefPtr<NGConstraintSpace> child_space = 264 RefPtr<NGConstraintSpace> child_space =
240 CreateConstraintSpaceForChild(child_bfc_offset, *child); 265 CreateConstraintSpaceForChild(*child, child_data);
241 RefPtr<NGLayoutResult> layout_result = 266 RefPtr<NGLayoutResult> layout_result =
242 child->Layout(child_space.Get(), child_break_token); 267 child->Layout(child_space.Get(), child_break_token);
243 FinishChildLayout(*child_space, child, layout_result.Get()); 268 previous_inflow_position =
269 FinishChildLayout(*child_space, previous_inflow_position, child_data,
270 child, layout_result.Get());
244 } 271 }
245 272
246 entry = child_iterator.NextChild(); 273 entry = child_iterator.NextChild();
247 child = entry.node; 274 child = entry.node;
248 child_break_token = entry.token; 275 child_break_token = entry.token;
249 276
250 if (IsOutOfSpace(ConstraintSpace(), content_size_)) 277 if (IsOutOfSpace(ConstraintSpace(), content_size_))
251 break; 278 break;
252 } 279 }
253 280
281 NGMarginStrut end_margin_strut = previous_inflow_position.margin_strut;
282 LayoutUnit end_bfc_block_offset = previous_inflow_position.bfc_block_offset;
283
254 // Margins collapsing: 284 // Margins collapsing:
255 // Bottom margins of an in-flow block box doesn't collapse with its last 285 // Bottom margins of an in-flow block box doesn't collapse with its last
256 // in-flow block-level child's bottom margin if the box has bottom 286 // in-flow block-level child's bottom margin if the box has bottom
257 // border/padding. 287 // border/padding.
258 content_size_ += border_and_padding_.block_end; 288 content_size_ += border_and_padding_.block_end;
259 if (border_and_padding_.block_end || 289 if (border_and_padding_.block_end ||
260 ConstraintSpace().IsNewFormattingContext()) { 290 ConstraintSpace().IsNewFormattingContext()) {
261 content_size_ += curr_margin_strut_.Sum(); 291 content_size_ += end_margin_strut.Sum();
262 curr_margin_strut_ = NGMarginStrut(); 292 end_margin_strut = NGMarginStrut();
263 } 293 }
264 294
265 // Recompute the block-axis size now that we know our content size. 295 // Recompute the block-axis size now that we know our content size.
266 size.block_size = 296 size.block_size =
267 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); 297 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_);
268 container_builder_.SetBlockSize(size.block_size); 298 container_builder_.SetBlockSize(size.block_size);
269 299
270 // Layout our absolute and fixed positioned children. 300 // Layout our absolute and fixed positioned children.
271 NGOutOfFlowLayoutPart(ConstraintSpace(), Style(), &container_builder_).Run(); 301 NGOutOfFlowLayoutPart(ConstraintSpace(), Style(), &container_builder_).Run();
272 302
273 // Non-empty blocks always know their position in space. 303 // Non-empty blocks always know their position in space.
274 // TODO(ikilpatrick): This check for a break token seems error prone. 304 // TODO(ikilpatrick): This check for a break token seems error prone.
275 if (size.block_size || BreakToken()) { 305 if (size.block_size || BreakToken()) {
276 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); 306 end_bfc_block_offset += end_margin_strut.Sum();
277 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, 307 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), end_bfc_block_offset,
278 &container_builder_); 308 &container_builder_);
279 PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_, 309 PositionPendingFloats(end_bfc_block_offset, &container_builder_,
280 MutableConstraintSpace()); 310 MutableConstraintSpace());
281 } 311 }
282 312
283 // Margins collapsing: 313 // Margins collapsing:
284 // Do not collapse margins between the last in-flow child and bottom margin 314 // Do not collapse margins between the last in-flow child and bottom margin
285 // of its parent if the parent has height != auto() 315 // of its parent if the parent has height != auto()
286 if (!Style().LogicalHeight().IsAuto()) { 316 if (!Style().LogicalHeight().IsAuto()) {
287 // TODO(glebl): handle minLogicalHeight, maxLogicalHeight. 317 // TODO(glebl): handle minLogicalHeight, maxLogicalHeight.
288 curr_margin_strut_ = NGMarginStrut(); 318 end_margin_strut = NGMarginStrut();
289 } 319 }
290 container_builder_.SetEndMarginStrut(curr_margin_strut_); 320 container_builder_.SetEndMarginStrut(end_margin_strut);
291 321
292 container_builder_.SetOverflowSize( 322 container_builder_.SetOverflowSize(
293 NGLogicalSize(max_inline_size_, content_size_)); 323 NGLogicalSize(max_inline_size_, content_size_));
294 324
295 // We only finalize for fragmentation if the fragment has a BFC offset. This 325 // We only finalize for fragmentation if the fragment has a BFC offset. This
296 // may occur with a zero block size fragment. We need to know the BFC offset 326 // may occur with a zero block size fragment. We need to know the BFC offset
297 // to determine where the fragmentation line is relative to us. 327 // to determine where the fragmentation line is relative to us.
298 if (container_builder_.BfcOffset() && 328 if (container_builder_.BfcOffset() &&
299 ConstraintSpace().HasBlockFragmentation()) 329 ConstraintSpace().HasBlockFragmentation())
300 FinalizeForFragmentation(); 330 FinalizeForFragmentation();
301 331
302 return container_builder_.ToBoxFragment(); 332 return container_builder_.ToBoxFragment();
303 } 333 }
304 334
305 void NGBlockLayoutAlgorithm::HandleOutOfFlowPositioned(NGBlockNode* child) { 335 void NGBlockLayoutAlgorithm::HandleOutOfFlowPositioned(
306 NGLogicalOffset offset = {border_and_padding_.inline_start, content_size_}; 336 const NGPreviousInflowPosition& previous_inflow_position,
337 NGBlockNode* child) {
338 NGLogicalOffset offset = {border_and_padding_.inline_start,
339 previous_inflow_position.logical_block_offset};
307 340
308 // We only include the margin strut in the OOF static-position if we know we 341 // We only include the margin strut in the OOF static-position if we know we
309 // aren't going to be a zero-block-size fragment. 342 // aren't going to be a zero-block-size fragment.
310 if (container_builder_.BfcOffset()) 343 if (container_builder_.BfcOffset())
311 offset.block_offset += curr_margin_strut_.Sum(); 344 offset.block_offset += previous_inflow_position.margin_strut.Sum();
312 345
313 container_builder_.AddOutOfFlowChildCandidate(child, offset); 346 container_builder_.AddOutOfFlowChildCandidate(child, offset);
314 } 347 }
315 348
316 void NGBlockLayoutAlgorithm::HandleFloating(NGBlockNode* child, 349 void NGBlockLayoutAlgorithm::HandleFloating(
317 NGBlockBreakToken* token) { 350 const NGPreviousInflowPosition& previous_inflow_position,
318 // TODO(ikilpatrick): Pass in BFC offset from previous in-flow child. 351 NGBlockNode* child,
319 curr_bfc_offset_ = container_builder_.BfcOffset() 352 NGBlockBreakToken* token) {
320 ? container_builder_.BfcOffset().value()
321 : ConstraintSpace().BfcOffset();
322 curr_bfc_offset_.block_offset += content_size_;
323
324 // Calculate margins in the BFC's writing mode. 353 // Calculate margins in the BFC's writing mode.
325 curr_child_margins_ = CalculateMargins(child); 354 NGBoxStrut margins = CalculateMargins(child);
326 355
327 NGLogicalOffset origin_offset = constraint_space_->BfcOffset(); 356 NGLogicalOffset origin_offset = constraint_space_->BfcOffset();
328 origin_offset.inline_offset += border_and_padding_.inline_start; 357 origin_offset.inline_offset += border_and_padding_.inline_start;
329 RefPtr<NGUnpositionedFloat> unpositioned_float = NGUnpositionedFloat::Create( 358 RefPtr<NGUnpositionedFloat> unpositioned_float = NGUnpositionedFloat::Create(
330 child_available_size_, child_percentage_size_, origin_offset, 359 child_available_size_, child_percentage_size_, origin_offset,
331 constraint_space_->BfcOffset(), curr_child_margins_, child, token); 360 constraint_space_->BfcOffset(), margins, child, token);
332 container_builder_.AddUnpositionedFloat(unpositioned_float); 361 container_builder_.AddUnpositionedFloat(unpositioned_float);
333 362
334 // If there is a break token for a float we must be resuming layout, we must 363 // If there is a break token for a float we must be resuming layout, we must
335 // always know our position in the BFC. 364 // always know our position in the BFC.
336 DCHECK(!token || container_builder_.BfcOffset()); 365 DCHECK(!token || container_builder_.BfcOffset());
337 366
338 // No need to postpone the positioning if we know the correct offset. 367 // No need to postpone the positioning if we know the correct offset.
339 if (container_builder_.BfcOffset()) { 368 if (container_builder_.BfcOffset()) {
340 NGLogicalOffset origin_point = curr_bfc_offset_;
341 // Adjust origin point to the margins of the last child. 369 // Adjust origin point to the margins of the last child.
342 // Example: <div style="margin-bottom: 20px"><float></div> 370 // Example: <div style="margin-bottom: 20px"><float></div>
343 // <div style="margin-bottom: 30px"></div> 371 // <div style="margin-bottom: 30px"></div>
344 origin_point.block_offset += curr_margin_strut_.Sum(); 372 LayoutUnit origin_block_offset =
345 PositionPendingFloats(origin_point.block_offset, &container_builder_, 373 previous_inflow_position.bfc_block_offset +
374 previous_inflow_position.margin_strut.Sum();
375 PositionPendingFloats(origin_block_offset, &container_builder_,
346 MutableConstraintSpace()); 376 MutableConstraintSpace());
347 } 377 }
348 } 378 }
349 379
350 NGLogicalOffset NGBlockLayoutAlgorithm::PrepareChildLayout( 380 NGInflowChildData NGBlockLayoutAlgorithm::PrepareChildLayout(
381 const NGPreviousInflowPosition& previous_inflow_position,
351 NGLayoutInputNode* child) { 382 NGLayoutInputNode* child) {
352 DCHECK(child); 383 DCHECK(child);
353 DCHECK(!child->IsFloating()); 384 DCHECK(!child->IsFloating());
354 385
355 // TODO(ikilpatrick): Pass in BFC offset from previous in-flow child. 386 LayoutUnit bfc_block_offset = previous_inflow_position.bfc_block_offset;
356 curr_bfc_offset_ = container_builder_.BfcOffset()
357 ? container_builder_.BfcOffset().value()
358 : ConstraintSpace().BfcOffset();
359 curr_bfc_offset_.block_offset += content_size_;
360 387
361 // Calculate margins in parent's writing mode. 388 // Calculate margins in parent's writing mode.
362 curr_child_margins_ = CalculateMargins(child); 389 NGBoxStrut margins = CalculateMargins(child);
390 NGMarginStrut margin_strut = previous_inflow_position.margin_strut;
363 391
364 bool should_position_pending_floats = 392 bool should_position_pending_floats =
365 !IsNewFormattingContextForBlockLevelChild(Style(), *child) && 393 !IsNewFormattingContextForBlockLevelChild(Style(), *child) &&
366 ClearanceMayAffectLayout(ConstraintSpace(), 394 ClearanceMayAffectLayout(ConstraintSpace(),
367 container_builder_.UnpositionedFloats(), 395 container_builder_.UnpositionedFloats(),
368 child->Style()); 396 child->Style());
369 397
370 // Children which may clear a float need to force all the pending floats to 398 // Children which may clear a float need to force all the pending floats to
371 // be positioned before layout. This also resolves the fragment's bfc offset. 399 // be positioned before layout. This also resolves the fragment's bfc offset.
372 if (should_position_pending_floats) { 400 if (should_position_pending_floats) {
373 LayoutUnit origin_point_block_offset = 401 LayoutUnit origin_point_block_offset =
374 curr_bfc_offset_.block_offset + curr_margin_strut_.Sum(); 402 bfc_block_offset + margin_strut.Sum();
375 MaybeUpdateFragmentBfcOffset( 403 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), origin_point_block_offset,
376 ConstraintSpace(), 404 &container_builder_);
377 {curr_bfc_offset_.inline_offset, origin_point_block_offset}, 405 // TODO(ikilpatrick): Check if origin_point_block_offset is correct -
378 &container_builder_); 406 // MaybeUpdateFragmentBfcOffset might have changed it due to clearance.
379 PositionPendingFloats(origin_point_block_offset, &container_builder_, 407 PositionPendingFloats(origin_point_block_offset, &container_builder_,
380 MutableConstraintSpace()); 408 MutableConstraintSpace());
381 } 409 }
382 410
383 NGLogicalOffset child_bfc_offset = curr_bfc_offset_; 411 NGLogicalOffset child_bfc_offset = {
384 child_bfc_offset.inline_offset += 412 ConstraintSpace().BfcOffset().inline_offset +
385 {border_and_padding_.inline_start + curr_child_margins_.inline_start}; 413 border_and_padding_.inline_start + margins.inline_start,
414 bfc_block_offset};
415
416 bool is_new_fc = IsNewFormattingContextForBlockLevelChild(Style(), *child);
386 417
387 // Append the current margin strut with child's block start margin. 418 // Append the current margin strut with child's block start margin.
388 // Non empty border/padding, and new FC use cases are handled inside of the 419 // Non empty border/padding, and new FC use cases are handled inside of the
389 // child's layout. 420 // child's layout.
390 if (!IsNewFormattingContextForBlockLevelChild(Style(), *child)) 421 if (!is_new_fc)
391 curr_margin_strut_.Append(curr_child_margins_.block_start); 422 margin_strut.Append(margins.block_start);
392 423
393 // TODO(crbug.com/716930): We should also collapse margins below once we 424 // TODO(crbug.com/716930): We should also collapse margins below once we
394 // remove LayoutInline splitting. 425 // remove LayoutInline splitting.
395 426
396 // Should collapse margins if our child is a legacy block. 427 // Should collapse margins if our child is a legacy block.
397 if (IsLegacyBlock(*child)) { 428 // TODO(ikilpatrick): I think this can be removed.
398 curr_bfc_offset_ += 429 if (IsLegacyBlock(*child) && !is_new_fc) {
399 {border_and_padding_.inline_start + curr_child_margins_.inline_start, 430 child_bfc_offset.block_offset += margin_strut.Sum();
400 curr_margin_strut_.Sum()}; 431 MaybeUpdateFragmentBfcOffset(
401 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, 432 ConstraintSpace(), child_bfc_offset.block_offset, &container_builder_);
402 &container_builder_); 433 // TODO(ikilpatrick): Check if child_bfc_offset.block_offset is correct -
403 PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_, 434 // MaybeUpdateFragmentBfcOffset might have changed it due to clearance.
435 PositionPendingFloats(child_bfc_offset.block_offset, &container_builder_,
404 MutableConstraintSpace()); 436 MutableConstraintSpace());
405 curr_margin_strut_ = {}; 437 margin_strut = {};
406 } 438 }
407 child_bfc_offset.block_offset = curr_bfc_offset_.block_offset; 439 return {child_bfc_offset, margin_strut, margins};
408 return child_bfc_offset;
409 } 440 }
410 441
411 void NGBlockLayoutAlgorithm::FinishChildLayout( 442 NGPreviousInflowPosition NGBlockLayoutAlgorithm::FinishChildLayout(
412 const NGConstraintSpace& child_space, 443 const NGConstraintSpace& child_space,
444 const NGPreviousInflowPosition& previous_inflow_position,
445 const NGInflowChildData& child_data,
413 const NGLayoutInputNode* child, 446 const NGLayoutInputNode* child,
414 NGLayoutResult* layout_result) { 447 NGLayoutResult* layout_result) {
415 // Pull out unpositioned floats to the current fragment. This may needed if 448 // Pull out unpositioned floats to the current fragment. This may needed if
416 // for example the child fragment could not position its floats because it's 449 // for example the child fragment could not position its floats because it's
417 // empty and therefore couldn't determine its position in space. 450 // empty and therefore couldn't determine its position in space.
418 container_builder_.MutableUnpositionedFloats().AppendVector( 451 container_builder_.MutableUnpositionedFloats().AppendVector(
419 layout_result->UnpositionedFloats()); 452 layout_result->UnpositionedFloats());
420 453
421 NGBoxFragment fragment( 454 NGBoxFragment fragment(
422 ConstraintSpace().WritingMode(), 455 ConstraintSpace().WritingMode(),
423 ToNGPhysicalBoxFragment(layout_result->PhysicalFragment().Get())); 456 ToNGPhysicalBoxFragment(layout_result->PhysicalFragment().Get()));
424 457
425 // Determine the fragment's position in the parent space. 458 // Determine the fragment's position in the parent space.
426 WTF::Optional<NGLogicalOffset> child_bfc_offset; 459 WTF::Optional<NGLogicalOffset> child_bfc_offset;
427 if (child_space.IsNewFormattingContext()) 460 if (child_space.IsNewFormattingContext())
428 child_bfc_offset = PositionNewFc(fragment, child_space); 461 child_bfc_offset = PositionNewFc(*child, previous_inflow_position, fragment,
462 child_data, child_space);
429 else if (fragment.BfcOffset()) 463 else if (fragment.BfcOffset())
430 child_bfc_offset = PositionWithBfcOffset(fragment); 464 child_bfc_offset = PositionWithBfcOffset(fragment);
431 else if (IsLegacyBlock(*child)) 465 else if (IsLegacyBlock(*child))
432 child_bfc_offset = PositionLegacy(child_space); 466 child_bfc_offset = PositionLegacy(child_space, child_data);
433 else if (container_builder_.BfcOffset()) 467 else if (container_builder_.BfcOffset())
434 child_bfc_offset = PositionWithParentBfc(child_space, fragment); 468 child_bfc_offset = PositionWithParentBfc(child_space, child_data, fragment);
435 469
436 NGLogicalOffset logical_offset = CalculateLogicalOffset(child_bfc_offset); 470 NGLogicalOffset logical_offset =
471 CalculateLogicalOffset(child_data.margins, child_bfc_offset);
437 472
438 // Update margin strut. 473 NGMarginStrut margin_strut = fragment.EndMarginStrut();
439 curr_margin_strut_ = fragment.EndMarginStrut(); 474 margin_strut.Append(child_data.margins.block_end);
440 curr_margin_strut_.Append(curr_child_margins_.block_end);
441 475
442 // Only modify content_size if BlockSize is not empty. It's needed to prevent 476 // Only modify content_size_ if the fragment's BlockSize is not empty. This is
443 // the situation when logical_offset is included in content_size for empty 477 // needed to prevent the situation when logical_offset is included in
444 // blocks. Example: 478 // content_size_ for empty blocks. Example:
445 // <div style="overflow:hidden"> 479 // <div style="overflow:hidden">
446 // <div style="margin-top: 8px"></div> 480 // <div style="margin-top: 8px"></div>
447 // <div style="margin-top: 10px"></div> 481 // <div style="margin-top: 10px"></div>
448 // </div> 482 // </div>
449 if (fragment.BlockSize()) 483 if (fragment.BlockSize())
450 content_size_ = fragment.BlockSize() + logical_offset.block_offset; 484 content_size_ = std::max(
451 max_inline_size_ = 485 content_size_, logical_offset.block_offset + fragment.BlockSize());
452 std::max(max_inline_size_, fragment.InlineSize() + 486 max_inline_size_ = std::max(
453 curr_child_margins_.InlineSum() + 487 max_inline_size_, fragment.InlineSize() + child_data.margins.InlineSum() +
454 border_and_padding_.InlineSum()); 488 border_and_padding_.InlineSum());
455 489
456 container_builder_.AddChild(layout_result, logical_offset); 490 container_builder_.AddChild(layout_result, logical_offset);
491
492 // Determine the child's end BFC block offset for the next child to use.
493 LayoutUnit child_end_bfc_block_offset;
494 if (child_bfc_offset) {
495 // TODO(crbug.com/716930): I think the fragment.BfcOffset() condition here
496 // can be removed once we've removed inline splitting.
497 if (fragment.BlockSize() || fragment.BfcOffset()) {
498 child_end_bfc_block_offset =
499 child_bfc_offset.value().block_offset + fragment.BlockSize();
500 } else {
501 DCHECK_EQ(LayoutUnit(), fragment.BlockSize());
502 child_end_bfc_block_offset = previous_inflow_position.bfc_block_offset;
503 }
504 } else {
505 child_end_bfc_block_offset = ConstraintSpace().BfcOffset().block_offset;
506 }
507
508 return {child_end_bfc_block_offset,
509 logical_offset.block_offset + fragment.BlockSize(), margin_strut};
457 } 510 }
458 511
459 NGLogicalOffset NGBlockLayoutAlgorithm::PositionNewFc( 512 NGLogicalOffset NGBlockLayoutAlgorithm::PositionNewFc(
513 const NGLayoutInputNode& child,
514 const NGPreviousInflowPosition& previous_inflow_position,
460 const NGBoxFragment& fragment, 515 const NGBoxFragment& fragment,
516 const NGInflowChildData& child_data,
461 const NGConstraintSpace& child_space) { 517 const NGConstraintSpace& child_space) {
518 const ComputedStyle& child_style = child.Style();
519
520 LayoutUnit child_bfc_offset_estimate =
521 child_data.bfc_offset_estimate.block_offset;
522
462 // 1. Position all pending floats to a temporary space. 523 // 1. Position all pending floats to a temporary space.
463 RefPtr<NGConstraintSpace> tmp_space = 524 RefPtr<NGConstraintSpace> tmp_space =
464 NGConstraintSpaceBuilder(&child_space) 525 NGConstraintSpaceBuilder(&child_space)
465 .SetIsNewFormattingContext(false) 526 .SetIsNewFormattingContext(false)
466 .ToConstraintSpace(child_space.WritingMode()); 527 .ToConstraintSpace(child_space.WritingMode());
467 PositionFloats(curr_bfc_offset_.block_offset, curr_bfc_offset_.block_offset, 528 PositionFloats(child_bfc_offset_estimate, child_bfc_offset_estimate,
468 curr_bfc_offset_.block_offset, 529 child_bfc_offset_estimate,
469 container_builder_.UnpositionedFloats(), tmp_space.Get()); 530 container_builder_.UnpositionedFloats(), tmp_space.Get());
470 531
471 NGLogicalOffset origin_offset = curr_bfc_offset_; 532 NGLogicalOffset origin_offset = {ConstraintSpace().BfcOffset().inline_offset +
472 origin_offset.inline_offset += border_and_padding_.inline_start; 533 border_and_padding_.inline_start,
534 child_bfc_offset_estimate};
535 AdjustToClearance(
536 GetClearanceOffset(ConstraintSpace().Exclusions(), child_style.Clear()),
537 &origin_offset);
473 538
474 // 2. Find an estimated layout opportunity for our fragment. 539 // 2. Find an estimated layout opportunity for our fragment.
475 NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment( 540 NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment(
476 tmp_space->Exclusions().get(), child_space.AvailableSize(), origin_offset, 541 tmp_space->Exclusions().get(), child_space.AvailableSize(), origin_offset,
477 curr_child_margins_, fragment.Size()); 542 child_data.margins, fragment.Size());
543
544 NGMarginStrut margin_strut = previous_inflow_position.margin_strut;
478 545
479 // 3. If the found opportunity lies on the same line with our estimated 546 // 3. If the found opportunity lies on the same line with our estimated
480 // child's BFC offset then merge fragment's margins with the current 547 // child's BFC offset then merge fragment's margins with the current
481 // MarginStrut. 548 // MarginStrut.
482 if (opportunity.offset.block_offset == curr_bfc_offset_.block_offset) 549 if (opportunity.offset.block_offset == child_bfc_offset_estimate)
483 curr_margin_strut_.Append(curr_child_margins_.block_start); 550 margin_strut.Append(child_data.margins.block_start);
484 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); 551 child_bfc_offset_estimate += margin_strut.Sum();
485 curr_margin_strut_ = {};
486 552
487 // 4. The child's BFC block offset is known here. 553 // 4. The child's BFC block offset is known here.
488 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, 554 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), child_bfc_offset_estimate,
489 &container_builder_); 555 &container_builder_);
490 PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_, 556 PositionPendingFloats(child_bfc_offset_estimate, &container_builder_,
491 MutableConstraintSpace()); 557 MutableConstraintSpace());
492 558
493 origin_offset = curr_bfc_offset_; 559 origin_offset = {ConstraintSpace().BfcOffset().inline_offset +
494 origin_offset.inline_offset += border_and_padding_.inline_start; 560 border_and_padding_.inline_start,
561 child_bfc_offset_estimate};
562 AdjustToClearance(
563 GetClearanceOffset(ConstraintSpace().Exclusions(), child_style.Clear()),
564 &origin_offset);
495 565
496 // 5. Find the final layout opportunity for the fragment after all pending 566 // 5. Find the final layout opportunity for the fragment after all pending
497 // floats are positioned at the correct BFC block's offset. 567 // floats are positioned at the correct BFC block's offset.
498 opportunity = FindLayoutOpportunityForFragment( 568 opportunity = FindLayoutOpportunityForFragment(
499 MutableConstraintSpace()->Exclusions().get(), child_space.AvailableSize(), 569 MutableConstraintSpace()->Exclusions().get(), child_space.AvailableSize(),
500 origin_offset, curr_child_margins_, fragment.Size()); 570 origin_offset, child_data.margins, fragment.Size());
501 571
502 curr_bfc_offset_ = opportunity.offset; 572 return opportunity.offset;
503 return curr_bfc_offset_;
504 } 573 }
505 574
506 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithBfcOffset( 575 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithBfcOffset(
507 const NGBoxFragment& fragment) { 576 const NGBoxFragment& fragment) {
508 DCHECK(fragment.BfcOffset()); 577 DCHECK(fragment.BfcOffset());
509 curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset; 578 LayoutUnit bfc_block_offset = fragment.BfcOffset().value().block_offset;
510 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, 579 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), bfc_block_offset,
511 &container_builder_); 580 &container_builder_);
512 PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_, 581 PositionPendingFloats(bfc_block_offset, &container_builder_,
513 MutableConstraintSpace()); 582 MutableConstraintSpace());
514 return fragment.BfcOffset().value(); 583 return fragment.BfcOffset().value();
515 } 584 }
516 585
517 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithParentBfc( 586 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithParentBfc(
518 const NGConstraintSpace& space, 587 const NGConstraintSpace& space,
588 const NGInflowChildData& child_data,
519 const NGBoxFragment& fragment) { 589 const NGBoxFragment& fragment) {
520 // The child must be an in-flow zero-block-size fragment, use its end margin 590 // The child must be an in-flow zero-block-size fragment, use its end margin
521 // strut for positioning. 591 // strut for positioning.
522 DCHECK(!fragment.BfcOffset()); 592 DCHECK(!fragment.BfcOffset());
523 DCHECK_EQ(fragment.BlockSize(), LayoutUnit()); 593 DCHECK_EQ(fragment.BlockSize(), LayoutUnit());
524 594
525 NGMarginStrut margin_strut = fragment.EndMarginStrut(); 595 NGMarginStrut margin_strut = fragment.EndMarginStrut();
526 margin_strut.Append(curr_child_margins_.block_end); 596 margin_strut.Append(child_data.margins.block_end);
527 597
528 curr_bfc_offset_ += 598 NGLogicalOffset bfc_offset = {
529 {border_and_padding_.inline_start + curr_child_margins_.inline_start, 599 ConstraintSpace().BfcOffset().inline_offset +
530 margin_strut.Sum()}; 600 border_and_padding_.inline_start + child_data.margins.inline_start,
531 AdjustToClearance(space.ClearanceOffset(), &curr_bfc_offset_); 601 child_data.bfc_offset_estimate.block_offset + margin_strut.Sum()};
532 PositionPendingFloatsFromOffset( 602 AdjustToClearance(space.ClearanceOffset(), &bfc_offset);
533 curr_bfc_offset_.block_offset, curr_bfc_offset_.block_offset, 603 PositionPendingFloatsFromOffset(bfc_offset.block_offset,
534 &container_builder_, MutableConstraintSpace()); 604 bfc_offset.block_offset, &container_builder_,
535 return curr_bfc_offset_; 605 MutableConstraintSpace());
606 return bfc_offset;
536 } 607 }
537 608
538 NGLogicalOffset NGBlockLayoutAlgorithm::PositionLegacy( 609 NGLogicalOffset NGBlockLayoutAlgorithm::PositionLegacy(
539 const NGConstraintSpace& child_space) { 610 const NGConstraintSpace& child_space,
540 AdjustToClearance(child_space.ClearanceOffset(), &curr_bfc_offset_); 611 const NGInflowChildData& child_data) {
541 return curr_bfc_offset_; 612 NGLogicalOffset bfc_offset = {ConstraintSpace().BfcOffset().inline_offset +
613 border_and_padding_.inline_start +
614 child_data.margins.inline_start,
615 child_data.bfc_offset_estimate.block_offset};
616 AdjustToClearance(child_space.ClearanceOffset(), &bfc_offset);
617 return bfc_offset;
542 } 618 }
543 619
544 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() { 620 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() {
545 LayoutUnit used_block_size = 621 LayoutUnit used_block_size =
546 BreakToken() ? BreakToken()->UsedBlockSize() : LayoutUnit(); 622 BreakToken() ? BreakToken()->UsedBlockSize() : LayoutUnit();
547 LayoutUnit block_size = ComputeBlockSizeForFragment( 623 LayoutUnit block_size = ComputeBlockSizeForFragment(
548 ConstraintSpace(), Style(), used_block_size + content_size_); 624 ConstraintSpace(), Style(), used_block_size + content_size_);
549 625
550 block_size -= used_block_size; 626 block_size -= used_block_size;
551 DCHECK_GE(block_size, LayoutUnit()) 627 DCHECK_GE(block_size, LayoutUnit())
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
602 sizes = child->ComputeMinMaxContentSize(); 678 sizes = child->ComputeMinMaxContentSize();
603 679
604 LayoutUnit child_inline_size = 680 LayoutUnit child_inline_size =
605 ComputeInlineSizeForFragment(*space, child_style, sizes); 681 ComputeInlineSizeForFragment(*space, child_style, sizes);
606 ApplyAutoMargins(*space, child_style, child_inline_size, &margins); 682 ApplyAutoMargins(*space, child_style, child_inline_size, &margins);
607 } 683 }
608 return margins; 684 return margins;
609 } 685 }
610 686
611 RefPtr<NGConstraintSpace> NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild( 687 RefPtr<NGConstraintSpace> NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
612 const NGLogicalOffset& child_bfc_offset, 688 const NGLayoutInputNode& child,
613 const NGLayoutInputNode& child) { 689 const NGInflowChildData& child_data) {
614 NGConstraintSpaceBuilder space_builder(MutableConstraintSpace()); 690 NGConstraintSpaceBuilder space_builder(MutableConstraintSpace());
615 space_builder.SetAvailableSize(child_available_size_) 691 space_builder.SetAvailableSize(child_available_size_)
616 .SetPercentageResolutionSize(child_percentage_size_); 692 .SetPercentageResolutionSize(child_percentage_size_);
617 693
618 const ComputedStyle& child_style = child.Style(); 694 const ComputedStyle& child_style = child.Style();
619 bool is_new_bfc = IsNewFormattingContextForBlockLevelChild(Style(), child); 695 bool is_new_bfc = IsNewFormattingContextForBlockLevelChild(Style(), child);
620 space_builder.SetIsNewFormattingContext(is_new_bfc) 696 space_builder.SetIsNewFormattingContext(is_new_bfc)
621 .SetBfcOffset(child_bfc_offset) 697 .SetBfcOffset(child_data.bfc_offset_estimate)
622 .SetMarginStrut(curr_margin_strut_); 698 .SetMarginStrut(child_data.margin_strut);
623 699
624 if (!is_new_bfc) { 700 if (!is_new_bfc) {
625 space_builder.SetUnpositionedFloats( 701 space_builder.SetUnpositionedFloats(
626 container_builder_.MutableUnpositionedFloats()); 702 container_builder_.MutableUnpositionedFloats());
627 } 703 }
628 704
629 if (child.IsInline()) { 705 if (child.IsInline()) {
630 // TODO(kojii): Setup space_builder appropriately for inline child. 706 // TODO(kojii): Setup space_builder appropriately for inline child.
631 space_builder.SetClearanceOffset(ConstraintSpace().ClearanceOffset()); 707 space_builder.SetClearanceOffset(ConstraintSpace().ClearanceOffset());
632 return space_builder.ToConstraintSpace( 708 return space_builder.ToConstraintSpace(
633 FromPlatformWritingMode(Style().GetWritingMode())); 709 FromPlatformWritingMode(Style().GetWritingMode()));
634 } 710 }
635 711
636 space_builder 712 space_builder
637 .SetClearanceOffset(GetClearanceOffset(constraint_space_->Exclusions(), 713 .SetClearanceOffset(GetClearanceOffset(constraint_space_->Exclusions(),
638 child_style.Clear())) 714 child_style.Clear()))
639 .SetIsShrinkToFit(ShouldShrinkToFit(Style(), child_style)) 715 .SetIsShrinkToFit(ShouldShrinkToFit(Style(), child_style))
640 .SetTextDirection(child_style.Direction()); 716 .SetTextDirection(child_style.Direction());
641 717
642 LayoutUnit space_available; 718 LayoutUnit space_available;
643 if (constraint_space_->HasBlockFragmentation()) { 719 if (constraint_space_->HasBlockFragmentation()) {
644 space_available = ConstraintSpace().FragmentainerSpaceAvailable(); 720 space_available = ConstraintSpace().FragmentainerSpaceAvailable();
645 // If a block establishes a new formatting context we must know our 721 // If a block establishes a new formatting context we must know our
646 // position in the formatting context, and are able to adjust the 722 // position in the formatting context, and are able to adjust the
647 // fragmentation line. 723 // fragmentation line.
648 if (is_new_bfc) { 724 if (is_new_bfc) {
649 space_available -= child_bfc_offset.block_offset; 725 space_available -= child_data.bfc_offset_estimate.block_offset;
650 } 726 }
651 } 727 }
652 space_builder.SetFragmentainerSpaceAvailable(space_available); 728 space_builder.SetFragmentainerSpaceAvailable(space_available);
653 729
654 return space_builder.ToConstraintSpace( 730 return space_builder.ToConstraintSpace(
655 FromPlatformWritingMode(child_style.GetWritingMode())); 731 FromPlatformWritingMode(child_style.GetWritingMode()));
656 } 732 }
657 } // namespace blink 733 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698