Commit 4e08b0af authored by Koji Ishii's avatar Koji Ishii Committed by Commit Bot

Use Is{First,Last}ForNode in MayHaveMultipleFragments

|MayHaveMultipleFragmentItems| turned out to be hot, and
|NGFragmentItem| version is slower than |NGPaintFragment|
version.

This patch uses |Is{First,Last}ForNode| flags added for the
block fragmentation. Also changes |FinalizeAfterLayout| to
compute them for non-block fragmented cases.

Bug: 982194
Change-Id: Idbc374b65ff39d877d727848431e50a521fe2008
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2203082
Commit-Queue: Koji Ishii <kojii@chromium.org>
Commit-Queue: Yoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#769619}
parent 47fd094f
...@@ -12,14 +12,6 @@ ...@@ -12,14 +12,6 @@
namespace blink { namespace blink {
namespace {
inline bool ShouldSetFirstAndLastForNode() {
return RuntimeEnabledFeatures::LayoutNGFragmentTraversalEnabled();
}
} // namespace
NGFragmentItems::NGFragmentItems(NGFragmentItemsBuilder* builder) NGFragmentItems::NGFragmentItems(NGFragmentItemsBuilder* builder)
: text_content_(std::move(builder->text_content_)), : text_content_(std::move(builder->text_content_)),
first_line_text_content_(std::move(builder->first_line_text_content_)), first_line_text_content_(std::move(builder->first_line_text_content_)),
...@@ -47,14 +39,17 @@ bool NGFragmentItems::IsSubSpan(const Span& span) const { ...@@ -47,14 +39,17 @@ bool NGFragmentItems::IsSubSpan(const Span& span) const {
void NGFragmentItems::FinalizeAfterLayout( void NGFragmentItems::FinalizeAfterLayout(
const Vector<scoped_refptr<const NGLayoutResult>, 1>& results) { const Vector<scoped_refptr<const NGLayoutResult>, 1>& results) {
HashMap<const LayoutObject*, const NGFragmentItem*> first_and_last; struct LastItem {
const NGFragmentItem* item;
wtf_size_t item_index;
};
HashMap<const LayoutObject*, LastItem> last_items;
for (const auto& result : results) { for (const auto& result : results) {
const auto& fragment = const auto& fragment =
To<NGPhysicalBoxFragment>(result->PhysicalFragment()); To<NGPhysicalBoxFragment>(result->PhysicalFragment());
const NGFragmentItems* current = fragment.Items(); const NGFragmentItems* current = fragment.Items();
if (UNLIKELY(!current)) if (UNLIKELY(!current))
continue; continue;
HashMap<const LayoutObject*, wtf_size_t> last_fragment_map;
const Span items = current->Items(); const Span items = current->Items();
wtf_size_t index = 0; wtf_size_t index = 0;
for (const scoped_refptr<const NGFragmentItem>& item : items) { for (const scoped_refptr<const NGFragmentItem>& item : items) {
...@@ -72,38 +67,43 @@ void NGFragmentItems::FinalizeAfterLayout( ...@@ -72,38 +67,43 @@ void NGFragmentItems::FinalizeAfterLayout(
DCHECK(layout_object->IsInLayoutNGInlineFormattingContext()) << *item; DCHECK(layout_object->IsInLayoutNGInlineFormattingContext()) << *item;
item->SetDeltaToNextForSameLayoutObject(0); item->SetDeltaToNextForSameLayoutObject(0);
if (ShouldSetFirstAndLastForNode()) { // TODO(layout-dev): Make this work for multiple box fragments (block
// fragmentation).
if (!fragment.IsFirstForNode()) {
bool is_first_for_node = bool is_first_for_node =
first_and_last.Set(layout_object, item.get()).is_new_entry; last_items.Set(layout_object, LastItem{item.get(), index})
.is_new_entry;
item->SetIsFirstForNode(is_first_for_node); item->SetIsFirstForNode(is_first_for_node);
item->SetIsLastForNode(false); item->SetIsLastForNode(false);
continue;
} }
// TODO(layout-dev): Make this work for multiple box fragments (block const auto last_item_result =
// fragmentation). last_items.insert(layout_object, LastItem{item.get(), index});
if (!fragment.IsFirstForNode())
continue;
auto insert_result = last_fragment_map.insert(layout_object, index); if (last_item_result.is_new_entry) {
if (insert_result.is_new_entry) { item->SetIsFirstForNode(true);
item->SetIsLastForNode(false);
DCHECK_EQ(layout_object->FirstInlineFragmentItemIndex(), 0u); DCHECK_EQ(layout_object->FirstInlineFragmentItemIndex(), 0u);
layout_object->SetFirstInlineFragmentItemIndex(index); layout_object->SetFirstInlineFragmentItemIndex(index);
continue; continue;
} }
const wtf_size_t last_index = insert_result.stored_value->value;
insert_result.stored_value->value = index; item->SetIsFirstForNode(false);
item->SetIsLastForNode(false);
LastItem* last = &last_item_result.stored_value->value;
const wtf_size_t last_index = last->item_index;
DCHECK_GT(last_index, 0u) << *item; DCHECK_GT(last_index, 0u) << *item;
DCHECK_LT(last_index, items.size()); DCHECK_LT(last_index, items.size());
DCHECK_LT(last_index, index); DCHECK_LT(last_index, index);
DCHECK_EQ(items[last_index - 1]->DeltaToNextForSameLayoutObject(), 0u); DCHECK_EQ(last->item->DeltaToNextForSameLayoutObject(), 0u);
items[last_index - 1]->SetDeltaToNextForSameLayoutObject(index - last->item->SetDeltaToNextForSameLayoutObject(index - last_index);
last_index); last->item = item.get();
last->item_index = index;
} }
} }
if (!ShouldSetFirstAndLastForNode()) for (const auto& iter : last_items)
return; iter.value.item->SetIsLastForNode(true);
for (const auto& iter : first_and_last)
iter.value->SetIsLastForNode(true);
} }
void NGFragmentItems::ClearAssociatedFragments(LayoutObject* container) { void NGFragmentItems::ClearAssociatedFragments(LayoutObject* container) {
......
...@@ -33,23 +33,16 @@ inline bool HasMultiplePaintFragments(const LayoutObject& layout_object) { ...@@ -33,23 +33,16 @@ inline bool HasMultiplePaintFragments(const LayoutObject& layout_object) {
return HasMultipleItems(NGPaintFragment::InlineFragmentsFor(&layout_object)); return HasMultipleItems(NGPaintFragment::InlineFragmentsFor(&layout_object));
} }
inline bool MayHaveMultipleFragmentItems(const LayoutObject& layout_object) { inline bool MayHaveMultipleFragmentItems(const NGFragmentItem& item,
// TODO(crbug.com/1061423): NGInlineCursor is currently unable to deal with const LayoutObject& layout_object) {
// objects split into multiple fragmentainers (e.g. columns). Just return true return !item.IsFirstForNode() || !item.IsLastForNode() ||
// if it's possible that this object participates in a fragmentation // TODO(crbug.com/1061423): NGInlineCursor is currently unable to deal
// context. This will give false positives, but that should be harmless, given // with objects split into multiple fragmentainers (e.g. columns). Just
// the way the return value is used by the caller. // return true if it's possible that this object participates in a
if (layout_object.IsInsideFlowThread()) // fragmentation context. This will give false positives, but that
return true; // should be harmless, given the way the return value is used by the
// caller.
NGInlineCursor cursor; UNLIKELY(layout_object.IsInsideFlowThread());
cursor.MoveTo(layout_object);
DCHECK(cursor);
if (cursor) {
cursor.MoveToNextForSameLayoutObject();
return cursor;
}
return false;
} }
} // namespace } // namespace
...@@ -121,9 +114,11 @@ void NGInlineBoxFragmentPainterBase::PaintBackgroundBorderShadow( ...@@ -121,9 +114,11 @@ void NGInlineBoxFragmentPainterBase::PaintBackgroundBorderShadow(
DCHECK(inline_box_fragment_.GetLayoutObject()); DCHECK(inline_box_fragment_.GetLayoutObject());
const LayoutObject& layout_object = *inline_box_fragment_.GetLayoutObject(); const LayoutObject& layout_object = *inline_box_fragment_.GetLayoutObject();
DCHECK(inline_box_paint_fragment_ || inline_box_item_);
bool object_may_have_multiple_boxes = bool object_may_have_multiple_boxes =
inline_box_paint_fragment_ ? HasMultiplePaintFragments(layout_object) inline_box_paint_fragment_
: MayHaveMultipleFragmentItems(layout_object); ? HasMultiplePaintFragments(layout_object)
: MayHaveMultipleFragmentItems(*inline_box_item_, layout_object);
// TODO(eae): Switch to LayoutNG version of BackgroundImageGeometry. // TODO(eae): Switch to LayoutNG version of BackgroundImageGeometry.
BackgroundImageGeometry geometry(*static_cast<const LayoutBoxModelObject*>( BackgroundImageGeometry geometry(*static_cast<const LayoutBoxModelObject*>(
......
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