Commit 48af0642 authored by Ian Kilpatrick's avatar Ian Kilpatrick Committed by Commit Bot

[FragmentItem] Build InlineContainingBlockGeometry from fragment items.

This adds a separate codepath for building up the inline containing
block information from fragment items, instead of the line-box tree.

I kept a separate codepath for ease of removal later.

Fixes ~15 tests.

Bug: 982194
Change-Id: Ibdaf708d4ca264071ab4b8b6b7099ad8a998e867
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2048707
Commit-Queue: Ian Kilpatrick <ikilpatrick@chromium.org>
Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#741744}
parent 1bb9e566
......@@ -30,8 +30,8 @@ void NGFragmentItemsBuilder::SetCurrentLine(
void NGFragmentItemsBuilder::AddLine(const NGPhysicalLineBoxFragment& line,
const LogicalOffset& offset) {
DCHECK_EQ(items_.size(), offsets_.size());
#if DCHECK_IS_ON()
DCHECK(!is_converted_to_physical_);
#if DCHECK_IS_ON()
DCHECK_EQ(current_line_fragment_, &line);
#endif
......@@ -65,6 +65,7 @@ void NGFragmentItemsBuilder::AddLine(const NGPhysicalLineBoxFragment& line,
void NGFragmentItemsBuilder::AddItems(Child* child_begin, Child* child_end) {
DCHECK_EQ(items_.size(), offsets_.size());
DCHECK(!is_converted_to_physical_);
for (Child* child_iter = child_begin; child_iter != child_end;) {
Child& child = *child_iter;
......@@ -134,6 +135,8 @@ void NGFragmentItemsBuilder::AddItems(Child* child_begin, Child* child_end) {
void NGFragmentItemsBuilder::AddListMarker(
const NGPhysicalBoxFragment& marker_fragment,
const LogicalOffset& offset) {
DCHECK(!is_converted_to_physical_);
// Resolved direction matters only for inline items, and outside list markers
// are not inline.
const TextDirection resolved_direction = TextDirection::kLtr;
......@@ -142,15 +145,22 @@ void NGFragmentItemsBuilder::AddListMarker(
offsets_.push_back(offset);
}
const Vector<std::unique_ptr<NGFragmentItem>>& NGFragmentItemsBuilder::Items(
WritingMode writing_mode,
TextDirection direction,
const PhysicalSize& outer_size) {
ConvertToPhysical(writing_mode, direction, outer_size);
return items_;
}
// Convert internal logical offsets to physical. Items are kept with logical
// offset until outer box size is determined.
void NGFragmentItemsBuilder::ConvertToPhysical(WritingMode writing_mode,
TextDirection direction,
const PhysicalSize& outer_size) {
CHECK_EQ(items_.size(), offsets_.size());
#if DCHECK_IS_ON()
DCHECK(!is_converted_to_physical_);
#endif
if (is_converted_to_physical_)
return;
// Children of lines have line-relative offsets. Use line-writing mode to
// convert their logical offsets.
......@@ -189,9 +199,7 @@ void NGFragmentItemsBuilder::ConvertToPhysical(WritingMode writing_mode,
}
}
#if DCHECK_IS_ON()
is_converted_to_physical_ = true;
#endif
}
void NGFragmentItemsBuilder::ToFragmentItems(WritingMode writing_mode,
......
......@@ -59,10 +59,18 @@ class CORE_EXPORT NGFragmentItemsBuilder {
void AddListMarker(const NGPhysicalBoxFragment& marker_fragment,
const LogicalOffset& offset);
// Converts the |NGFragmentItem| vector to the physical coordinate space and
// returns the result. This should only be used for determining the inline
// containing block geometry for OOF-positioned nodes.
//
// Once this method has been called, new items cannot be added.
const Vector<std::unique_ptr<NGFragmentItem>>&
Items(WritingMode, TextDirection, const PhysicalSize& outer_size);
// Build a |NGFragmentItems|. The builder cannot build twice because data set
// to this builder may be cleared.
void ToFragmentItems(WritingMode writing_mode,
TextDirection direction,
void ToFragmentItems(WritingMode,
TextDirection,
const PhysicalSize& outer_size,
void* data);
......@@ -84,10 +92,10 @@ class CORE_EXPORT NGFragmentItemsBuilder {
ChildList current_line_;
bool has_floating_descendants_for_paint_ = false;
bool is_converted_to_physical_ = false;
#if DCHECK_IS_ON()
const NGPhysicalLineBoxFragment* current_line_fragment_ = nullptr;
bool is_converted_to_physical_ = false;
#endif
friend class NGFragmentItems;
......
......@@ -77,6 +77,68 @@ void GatherInlineContainerFragmentsFromLinebox(
}
}
void GatherInlineContainerFragmentsFromItems(
const Vector<std::unique_ptr<NGFragmentItem>>& items,
NGBoxFragmentBuilder::InlineContainingBlockMap* inline_containing_block_map,
HashMap<const LayoutObject*, LineBoxPair>* containing_linebox_map) {
const NGPhysicalLineBoxFragment* linebox = nullptr;
for (const auto& item : items) {
// Track the current linebox.
if (const NGPhysicalLineBoxFragment* current_linebox =
item->LineBoxFragment()) {
linebox = current_linebox;
continue;
}
// We only care about inlines which have generated a box fragment.
const NGPhysicalBoxFragment* box = item->BoxFragment();
if (!box)
continue;
// The key for the inline is the continuation root if it exists.
const LayoutObject* key = box->GetLayoutObject();
if (key->IsLayoutInline() && key->GetNode())
key = key->ContinuationRoot();
// See if we need the containing block information for this inline.
auto it = inline_containing_block_map->find(key);
if (it == inline_containing_block_map->end())
continue;
base::Optional<NGBoxFragmentBuilder::InlineContainingBlockGeometry>&
containing_block_geometry = it->value;
LineBoxPair& containing_lineboxes =
containing_linebox_map->insert(key, LineBoxPair{nullptr, nullptr})
.stored_value->value;
DCHECK(containing_block_geometry.has_value() ||
!containing_lineboxes.first);
PhysicalRect fragment_rect = item->RectInContainerBlock();
if (containing_lineboxes.first == linebox) {
// Unite the start rect with the fragment's rect.
containing_block_geometry->start_fragment_union_rect.Unite(fragment_rect);
} else if (!containing_lineboxes.first) {
DCHECK(!containing_lineboxes.second);
// This is the first linebox we've encountered, initialize the containing
// block geometry.
containing_lineboxes.first = linebox;
containing_lineboxes.second = linebox;
containing_block_geometry =
NGBoxFragmentBuilder::InlineContainingBlockGeometry{fragment_rect,
fragment_rect};
}
if (containing_lineboxes.second == linebox) {
// Unite the end rect with the fragment's rect.
containing_block_geometry->end_fragment_union_rect.Unite(fragment_rect);
} else if (!linebox->IsEmptyLineBox()) {
// We've found a new "end" linebox, update the containing block geometry.
containing_lineboxes.second = linebox;
containing_block_geometry->end_fragment_union_rect = fragment_rect;
}
}
}
} // namespace
void NGBoxFragmentBuilder::AddBreakBeforeChild(
......@@ -242,10 +304,7 @@ scoped_refptr<const NGLayoutResult> NGBoxFragmentBuilder::Abort(
NGLayoutResult::NGBoxFragmentBuilderPassKey(), status, this));
}
// Computes the geometry required for any inline containing blocks.
// |inline_containing_block_map| is a map whose keys specify which inline
// containing block geometry is required.
void NGBoxFragmentBuilder::ComputeInlineContainerFragments(
void NGBoxFragmentBuilder::ComputeInlineContainerGeometryFromFragmentTree(
InlineContainingBlockMap* inline_containing_block_map) {
if (inline_containing_block_map->IsEmpty())
return;
......@@ -301,6 +360,54 @@ void NGBoxFragmentBuilder::ComputeInlineContainerFragments(
}
}
void NGBoxFragmentBuilder::ComputeInlineContainerGeometry(
InlineContainingBlockMap* inline_containing_block_map) {
if (inline_containing_block_map->IsEmpty())
return;
// This function requires that we have the final size of the fragment set
// upon the builder.
DCHECK_GE(InlineSize(), LayoutUnit());
DCHECK_GE(BlockSize(), LayoutUnit());
#if DCHECK_IS_ON()
// Make sure all entries are a continuation root.
for (const auto& entry : *inline_containing_block_map)
DCHECK_EQ(entry.key, entry.key->ContinuationRoot());
#endif
HashMap<const LayoutObject*, LineBoxPair> containing_linebox_map;
if (items_builder_) {
// To access the items correctly we need to convert them to the physical
// coordinate space.
GatherInlineContainerFragmentsFromItems(
items_builder_->Items(GetWritingMode(), Direction(),
ToPhysicalSize(Size(), GetWritingMode())),
inline_containing_block_map, &containing_linebox_map);
return;
}
// If we have children which are anonymous block, we might contain split
// inlines, this can occur in the following example:
// <div>
// Some text <span style="position: relative;">text
// <div>block</div>
// text </span> text.
// </div>
for (const auto& child : children_) {
if (!child.fragment->IsAnonymousBlock())
continue;
const auto* items = To<NGPhysicalBoxFragment>(*child.fragment).Items();
if (!items)
continue;
GatherInlineContainerFragmentsFromItems(
items->Items(), inline_containing_block_map, &containing_linebox_map);
}
}
#if DCHECK_IS_ON()
void NGBoxFragmentBuilder::CheckNoBlockFragmentation() const {
......
......@@ -275,8 +275,8 @@ class CORE_EXPORT NGBoxFragmentBuilder final
items_builder_ = builder;
}
// Inline containing block geometry is defined by two rectangles defined
// by fragments generated by LayoutInline.
// Inline containing block geometry is defined by two rectangles, generated
// by fragments of the LayoutInline.
struct InlineContainingBlockGeometry {
DISALLOW_NEW();
// Union of fragments generated on the first line.
......@@ -288,7 +288,13 @@ class CORE_EXPORT NGBoxFragmentBuilder final
using InlineContainingBlockMap =
HashMap<const LayoutObject*,
base::Optional<InlineContainingBlockGeometry>>;
void ComputeInlineContainerFragments(
// Computes the geometry required for any inline containing blocks.
// |inline_containing_block_map| is a map whose keys specify which inline
// containing block geometry is required.
void ComputeInlineContainerGeometryFromFragmentTree(
InlineContainingBlockMap* inline_containing_block_map);
void ComputeInlineContainerGeometry(
InlineContainingBlockMap* inline_containing_block_map);
#if DCHECK_IS_ON()
......
......@@ -291,22 +291,22 @@ void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks(
inline_geometry);
}
}
// Fetch start/end fragment info.
container_builder_->ComputeInlineContainerFragments(
&inline_container_fragments);
// Fetch the inline start/end fragment geometry.
if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
container_builder_->ComputeInlineContainerGeometry(
&inline_container_fragments);
} else {
container_builder_->ComputeInlineContainerGeometryFromFragmentTree(
&inline_container_fragments);
}
LogicalSize container_builder_size = container_builder_->Size();
PhysicalSize container_builder_physical_size =
ToPhysicalSize(container_builder_size, writing_mode_);
// Translate start/end fragments into ContainingBlockInfo.
// Transform the start/end fragments into a ContainingBlockInfo.
for (auto& block_info : inline_container_fragments) {
// Variables needed to describe ContainingBlockInfo
const ComputedStyle* inline_cb_style = block_info.key->Style();
LogicalSize inline_cb_size;
LogicalOffset container_offset;
DCHECK(block_info.value.has_value());
DCHECK(inline_cb_style);
NGBoxStrut inline_cb_borders = ComputeBordersForInline(*inline_cb_style);
// The calculation below determines the size of the inline containing block
// rect.
......@@ -360,7 +360,11 @@ void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks(
//
// Note in cases [2a, 2b] we don't allow a "negative" containing block size,
// we clamp negative sizes to zero.
const ComputedStyle* inline_cb_style = block_info.key->Style();
DCHECK(inline_cb_style);
TextDirection container_direction = default_containing_block_.direction;
NGBoxStrut inline_cb_borders = ComputeBordersForInline(*inline_cb_style);
bool is_same_direction =
container_direction == inline_cb_style->Direction();
......@@ -401,13 +405,14 @@ void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks(
// Step 3 - determine the logical rectangle.
// Determine the logical size of the containing block.
inline_cb_size = {end_offset.inline_offset - start_offset.inline_offset,
end_offset.block_offset - start_offset.block_offset};
LogicalSize inline_cb_size = {
end_offset.inline_offset - start_offset.inline_offset,
end_offset.block_offset - start_offset.block_offset};
DCHECK_GE(inline_cb_size.inline_size, LayoutUnit());
DCHECK_GE(inline_cb_size.block_size, LayoutUnit());
// Set the container padding-box offset.
container_offset = start_offset;
LogicalOffset container_offset = start_offset;
containing_blocks_map_.insert(
block_info.key,
......
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