Commit a0a58167 authored by Morten Stenshorne's avatar Morten Stenshorne Committed by Commit Bot

[LayoutNG] Position OOFs before layout.

Shuffle code around in LayoutDescendant(), so that we know the size
before (final) layout. Block fragmentation requires that we know the
block-start offset before layout, so that the fragmentation machinery
knows where fragmentainers end.

One exception is centered dialogs. Those cannot occur inside block
fragmentation, so I left that piece of code after layout, rather than
fixing it (would require some trivial amount of work, but it just
doesn't seem worth it).

Bug: 829028
Change-Id: I2491507327c5443aaec398682b5bca30d0d3d295
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1670881Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Reviewed-by: default avatarAleks Totic <atotic@chromium.org>
Commit-Queue: Morten Stenshorne <mstensho@chromium.org>
Cr-Commit-Position: refs/heads/master@{#671529}
parent 07d81d8e
......@@ -465,6 +465,7 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::LayoutDescendant(
NGStaticPosition static_position(descendant.static_position);
static_position.offset -= container_info.physical_container_offset;
// Need a constraint space to resolve offsets.
NGConstraintSpace descendant_constraint_space =
NGConstraintSpaceBuilder(container_writing_mode, descendant_writing_mode,
/* is_new_fc */ true)
......@@ -482,6 +483,14 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::LayoutDescendant(
base::Optional<MinMaxSize> min_max_size;
scoped_refptr<const NGLayoutResult> layout_result = nullptr;
// In order to calculate the offsets, we may need to know the size.
// In some cases we will need the fragment size in order to calculate the
// offset. We may have to lay out to get the fragment size. For block
// fragmentation, we *need* to know the block-offset before layout. In other
// words, in that case, we may have to lay out, calculate the offset, and
// then lay out again at the correct block-offset.
bool is_replaced = node.IsReplaced();
bool should_be_considered_as_replaced = node.ShouldBeConsideredAsReplaced();
......@@ -526,11 +535,77 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::LayoutDescendant(
block_estimate = fragment.BlockSize();
}
// Calculate the offsets.
ComputeFullAbsoluteWithChildBlockSize(
descendant_constraint_space, descendant_style, border_padding,
static_position, block_estimate, replaced_size, container_writing_mode,
container_style.Direction(), &node_position);
NGBoxStrut inset = node_position.inset.ConvertToLogical(
container_writing_mode, default_containing_block_.style->Direction());
// |inset| is relative to the container's padding-box. Convert this to being
// relative to the default container's border-box.
LogicalOffset offset = container_info.container_offset;
offset.inline_offset += inset.inline_start;
offset.block_offset += inset.block_start;
if (!only_layout) {
// Special case: oof css container is a split inline.
// When css container spans multiple anonymous blocks, its dimensions can
// only be computed by a block that is an ancestor of all fragments
// generated by css container. That block is parent of anonymous containing
// block.
// That is why instead of OOF being placed by its anonymous container,
// they get placed by anonymous container's parent.
// This is different from all other OOF blocks, and requires special
// handling in several places in the OOF code.
// There is an exception to special case: if anonymous block is Legacy, we
// cannot do the fancy multiple anonymous block traversal, and we handle it
// like regular blocks.
//
// Detailed example:
//
// If Layout tree looks like this:
// LayoutNGBlockFlow#container
// LayoutNGBlockFlow (anonymous#1)
// LayoutInline#1 (relative)
// LayoutNGBlockFlow (anonymous#2 relative)
// LayoutNGBlockFlow#oof (positioned)
// LayoutNGBlockFlow (anonymous#3)
// LayoutInline#3 (continuation)
//
// The containing block geometry is defined by split inlines,
// LayoutInline#1, LayoutInline#3.
// Css container anonymous#2 does not have information needed
// to compute containing block geometry.
// Therefore, #oof cannot be placed by anonymous#2. NG handles this case
// by placing #oof in parent of anonymous (#container).
//
// But, PaintPropertyTreeBuilder expects #oof.Location() to be wrt css
// container, #anonymous2. This is why the code below adjusts the legacy
// offset from being wrt #container to being wrt #anonymous2.
const LayoutObject* container = node.GetLayoutBox()->Container();
if (container->IsAnonymousBlock()) {
LogicalOffset container_offset =
container_builder_->GetChildOffset(container);
offset -= container_offset;
} else if (container->IsLayoutInline() &&
container->ContainingBlock()->IsAnonymousBlock()) {
// Location of OOF with inline container, and anonymous containing block
// is wrt container.
LogicalOffset container_offset =
container_builder_->GetChildOffset(container->ContainingBlock());
offset -= container_offset;
}
}
// We have calculated the offsets, and if we need to lay out, we can do so at
// the correct block-start offset now.
// TODO(mstensho): Actually pass the block-start offset to layout.
// Skip this step if we produced a fragment when estimating the block-size.
if (!layout_result) {
block_estimate =
......@@ -551,78 +626,18 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::LayoutDescendant(
->IsDisplayFlexibleOrGridBox())
node.GetLayoutBox()->SetMargin(node_position.margins);
NGBoxStrut inset = node_position.inset.ConvertToLogical(
container_writing_mode, default_containing_block_.style->Direction());
// |inset| is relative to the container's padding-box. Convert this to being
// relative to the default container's border-box.
LogicalOffset offset = container_info.container_offset;
offset.inline_offset += inset.inline_start;
offset.block_offset += inset.block_start;
// Adjusting the offset for a dialog after layout is fine, since we cannot
// have dialogs needing alignment inside block fragmentation.
base::Optional<LayoutUnit> y = ComputeAbsoluteDialogYPosition(
*node.GetLayoutBox(), layout_result->PhysicalFragment().Size().height);
if (y.has_value()) {
DCHECK(!container_space_.HasBlockFragmentation());
if (IsHorizontalWritingMode(container_writing_mode))
offset.block_offset = *y;
else
offset.inline_offset = *y;
}
if (only_layout) {
layout_result->GetMutableForOutOfFlow().SetOutOfFlowPositionedOffset(
offset);
return layout_result;
}
// Special case: oof css container is a split inline.
// When css container spans multiple anonymous blocks, its dimensions
// can only be computed by a block that is an ancestor of all fragments
// generated by css container. That block is parent of anonymous containing
// block.
// That is why instead of OOF being placed by its anonymous container,
// they get placed by anonymous container's parent.
// This is different from all other OOF blocks, and requires special
// handling in several places in the OOF code.
// There is an exception to special case: if anonymous block is Legacy,
// we cannot do the fancy multiple anonymous block traversal, and we handle
// it like regular blocks.
//
// Detailed example:
//
// If Layout tree looks like this:
// LayoutNGBlockFlow#container
// LayoutNGBlockFlow (anonymous#1)
// LayoutInline#1 (relative)
// LayoutNGBlockFlow (anonymous#2 relative)
// LayoutNGBlockFlow#oof (positioned)
// LayoutNGBlockFlow (anonymous#3)
// LayoutInline#3 (continuation)
//
// The containing block geometry is defined by split inlines,
// LayoutInline#1, LayoutInline#3.
// Css container anonymous#2 does not have information needed
// to compute containing block geometry.
// Therefore, #oof cannot be placed by anonymous#2. NG handles this case
// by placing #oof in parent of anonymous (#container).
//
// But, PaintPropertyTreeBuilder expects #oof.Location() to be wrt
// css container, #anonymous2. This is why the code below adjusts
// the legacy offset from being wrt #container to being wrt #anonymous2.
const LayoutObject* container = node.GetLayoutBox()->Container();
if (container->IsAnonymousBlock()) {
LogicalOffset container_offset =
container_builder_->GetChildOffset(container);
offset -= container_offset;
} else if (container->IsLayoutInline() &&
container->ContainingBlock()->IsAnonymousBlock()) {
// Location of OOF with inline container, and anonymous containing block
// is wrt container.
LogicalOffset container_offset =
container_builder_->GetChildOffset(container->ContainingBlock());
offset -= container_offset;
}
layout_result->GetMutableForOutOfFlow().SetOutOfFlowPositionedOffset(offset);
return layout_result;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment