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( ...@@ -30,8 +30,8 @@ void NGFragmentItemsBuilder::SetCurrentLine(
void NGFragmentItemsBuilder::AddLine(const NGPhysicalLineBoxFragment& line, void NGFragmentItemsBuilder::AddLine(const NGPhysicalLineBoxFragment& line,
const LogicalOffset& offset) { const LogicalOffset& offset) {
DCHECK_EQ(items_.size(), offsets_.size()); DCHECK_EQ(items_.size(), offsets_.size());
#if DCHECK_IS_ON()
DCHECK(!is_converted_to_physical_); DCHECK(!is_converted_to_physical_);
#if DCHECK_IS_ON()
DCHECK_EQ(current_line_fragment_, &line); DCHECK_EQ(current_line_fragment_, &line);
#endif #endif
...@@ -65,6 +65,7 @@ void NGFragmentItemsBuilder::AddLine(const NGPhysicalLineBoxFragment& line, ...@@ -65,6 +65,7 @@ void NGFragmentItemsBuilder::AddLine(const NGPhysicalLineBoxFragment& line,
void NGFragmentItemsBuilder::AddItems(Child* child_begin, Child* child_end) { void NGFragmentItemsBuilder::AddItems(Child* child_begin, Child* child_end) {
DCHECK_EQ(items_.size(), offsets_.size()); DCHECK_EQ(items_.size(), offsets_.size());
DCHECK(!is_converted_to_physical_);
for (Child* child_iter = child_begin; child_iter != child_end;) { for (Child* child_iter = child_begin; child_iter != child_end;) {
Child& child = *child_iter; Child& child = *child_iter;
...@@ -134,6 +135,8 @@ void NGFragmentItemsBuilder::AddItems(Child* child_begin, Child* child_end) { ...@@ -134,6 +135,8 @@ void NGFragmentItemsBuilder::AddItems(Child* child_begin, Child* child_end) {
void NGFragmentItemsBuilder::AddListMarker( void NGFragmentItemsBuilder::AddListMarker(
const NGPhysicalBoxFragment& marker_fragment, const NGPhysicalBoxFragment& marker_fragment,
const LogicalOffset& offset) { const LogicalOffset& offset) {
DCHECK(!is_converted_to_physical_);
// Resolved direction matters only for inline items, and outside list markers // Resolved direction matters only for inline items, and outside list markers
// are not inline. // are not inline.
const TextDirection resolved_direction = TextDirection::kLtr; const TextDirection resolved_direction = TextDirection::kLtr;
...@@ -142,15 +145,22 @@ void NGFragmentItemsBuilder::AddListMarker( ...@@ -142,15 +145,22 @@ void NGFragmentItemsBuilder::AddListMarker(
offsets_.push_back(offset); 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 // Convert internal logical offsets to physical. Items are kept with logical
// offset until outer box size is determined. // offset until outer box size is determined.
void NGFragmentItemsBuilder::ConvertToPhysical(WritingMode writing_mode, void NGFragmentItemsBuilder::ConvertToPhysical(WritingMode writing_mode,
TextDirection direction, TextDirection direction,
const PhysicalSize& outer_size) { const PhysicalSize& outer_size) {
CHECK_EQ(items_.size(), offsets_.size()); CHECK_EQ(items_.size(), offsets_.size());
#if DCHECK_IS_ON() if (is_converted_to_physical_)
DCHECK(!is_converted_to_physical_); return;
#endif
// Children of lines have line-relative offsets. Use line-writing mode to // Children of lines have line-relative offsets. Use line-writing mode to
// convert their logical offsets. // convert their logical offsets.
...@@ -189,9 +199,7 @@ void NGFragmentItemsBuilder::ConvertToPhysical(WritingMode writing_mode, ...@@ -189,9 +199,7 @@ void NGFragmentItemsBuilder::ConvertToPhysical(WritingMode writing_mode,
} }
} }
#if DCHECK_IS_ON()
is_converted_to_physical_ = true; is_converted_to_physical_ = true;
#endif
} }
void NGFragmentItemsBuilder::ToFragmentItems(WritingMode writing_mode, void NGFragmentItemsBuilder::ToFragmentItems(WritingMode writing_mode,
......
...@@ -59,10 +59,18 @@ class CORE_EXPORT NGFragmentItemsBuilder { ...@@ -59,10 +59,18 @@ class CORE_EXPORT NGFragmentItemsBuilder {
void AddListMarker(const NGPhysicalBoxFragment& marker_fragment, void AddListMarker(const NGPhysicalBoxFragment& marker_fragment,
const LogicalOffset& offset); 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 // Build a |NGFragmentItems|. The builder cannot build twice because data set
// to this builder may be cleared. // to this builder may be cleared.
void ToFragmentItems(WritingMode writing_mode, void ToFragmentItems(WritingMode,
TextDirection direction, TextDirection,
const PhysicalSize& outer_size, const PhysicalSize& outer_size,
void* data); void* data);
...@@ -84,10 +92,10 @@ class CORE_EXPORT NGFragmentItemsBuilder { ...@@ -84,10 +92,10 @@ class CORE_EXPORT NGFragmentItemsBuilder {
ChildList current_line_; ChildList current_line_;
bool has_floating_descendants_for_paint_ = false; bool has_floating_descendants_for_paint_ = false;
bool is_converted_to_physical_ = false;
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
const NGPhysicalLineBoxFragment* current_line_fragment_ = nullptr; const NGPhysicalLineBoxFragment* current_line_fragment_ = nullptr;
bool is_converted_to_physical_ = false;
#endif #endif
friend class NGFragmentItems; friend class NGFragmentItems;
......
...@@ -77,6 +77,68 @@ void GatherInlineContainerFragmentsFromLinebox( ...@@ -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 } // namespace
void NGBoxFragmentBuilder::AddBreakBeforeChild( void NGBoxFragmentBuilder::AddBreakBeforeChild(
...@@ -242,10 +304,7 @@ scoped_refptr<const NGLayoutResult> NGBoxFragmentBuilder::Abort( ...@@ -242,10 +304,7 @@ scoped_refptr<const NGLayoutResult> NGBoxFragmentBuilder::Abort(
NGLayoutResult::NGBoxFragmentBuilderPassKey(), status, this)); NGLayoutResult::NGBoxFragmentBuilderPassKey(), status, this));
} }
// Computes the geometry required for any inline containing blocks. void NGBoxFragmentBuilder::ComputeInlineContainerGeometryFromFragmentTree(
// |inline_containing_block_map| is a map whose keys specify which inline
// containing block geometry is required.
void NGBoxFragmentBuilder::ComputeInlineContainerFragments(
InlineContainingBlockMap* inline_containing_block_map) { InlineContainingBlockMap* inline_containing_block_map) {
if (inline_containing_block_map->IsEmpty()) if (inline_containing_block_map->IsEmpty())
return; return;
...@@ -301,6 +360,54 @@ void NGBoxFragmentBuilder::ComputeInlineContainerFragments( ...@@ -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() #if DCHECK_IS_ON()
void NGBoxFragmentBuilder::CheckNoBlockFragmentation() const { void NGBoxFragmentBuilder::CheckNoBlockFragmentation() const {
......
...@@ -275,8 +275,8 @@ class CORE_EXPORT NGBoxFragmentBuilder final ...@@ -275,8 +275,8 @@ class CORE_EXPORT NGBoxFragmentBuilder final
items_builder_ = builder; items_builder_ = builder;
} }
// Inline containing block geometry is defined by two rectangles defined // Inline containing block geometry is defined by two rectangles, generated
// by fragments generated by LayoutInline. // by fragments of the LayoutInline.
struct InlineContainingBlockGeometry { struct InlineContainingBlockGeometry {
DISALLOW_NEW(); DISALLOW_NEW();
// Union of fragments generated on the first line. // Union of fragments generated on the first line.
...@@ -288,7 +288,13 @@ class CORE_EXPORT NGBoxFragmentBuilder final ...@@ -288,7 +288,13 @@ class CORE_EXPORT NGBoxFragmentBuilder final
using InlineContainingBlockMap = using InlineContainingBlockMap =
HashMap<const LayoutObject*, HashMap<const LayoutObject*,
base::Optional<InlineContainingBlockGeometry>>; 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); InlineContainingBlockMap* inline_containing_block_map);
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
......
...@@ -291,22 +291,22 @@ void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks( ...@@ -291,22 +291,22 @@ void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks(
inline_geometry); inline_geometry);
} }
} }
// Fetch start/end fragment info.
container_builder_->ComputeInlineContainerFragments( // Fetch the inline start/end fragment geometry.
&inline_container_fragments); if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
container_builder_->ComputeInlineContainerGeometry(
&inline_container_fragments);
} else {
container_builder_->ComputeInlineContainerGeometryFromFragmentTree(
&inline_container_fragments);
}
LogicalSize container_builder_size = container_builder_->Size(); LogicalSize container_builder_size = container_builder_->Size();
PhysicalSize container_builder_physical_size = PhysicalSize container_builder_physical_size =
ToPhysicalSize(container_builder_size, writing_mode_); 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) { 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(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 // The calculation below determines the size of the inline containing block
// rect. // rect.
...@@ -360,7 +360,11 @@ void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks( ...@@ -360,7 +360,11 @@ void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks(
// //
// Note in cases [2a, 2b] we don't allow a "negative" containing block size, // Note in cases [2a, 2b] we don't allow a "negative" containing block size,
// we clamp negative sizes to zero. // 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; TextDirection container_direction = default_containing_block_.direction;
NGBoxStrut inline_cb_borders = ComputeBordersForInline(*inline_cb_style);
bool is_same_direction = bool is_same_direction =
container_direction == inline_cb_style->Direction(); container_direction == inline_cb_style->Direction();
...@@ -401,13 +405,14 @@ void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks( ...@@ -401,13 +405,14 @@ void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks(
// Step 3 - determine the logical rectangle. // Step 3 - determine the logical rectangle.
// Determine the logical size of the containing block. // Determine the logical size of the containing block.
inline_cb_size = {end_offset.inline_offset - start_offset.inline_offset, LogicalSize inline_cb_size = {
end_offset.block_offset - start_offset.block_offset}; 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.inline_size, LayoutUnit());
DCHECK_GE(inline_cb_size.block_size, LayoutUnit()); DCHECK_GE(inline_cb_size.block_size, LayoutUnit());
// Set the container padding-box offset. // Set the container padding-box offset.
container_offset = start_offset; LogicalOffset container_offset = start_offset;
containing_blocks_map_.insert( containing_blocks_map_.insert(
block_info.key, 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