Commit bc03a748 authored by Koji Ishii's avatar Koji Ishii Committed by Commit Bot

[NGFragmentItem] Add NGFragmentItem::ItemsFor()

This patch adds |NGFragmentItem::ItemsFor()| that retrieves
|NGFragmentItem| associated with a |LayoutObject|.

The plan is to store the index to |LayoutObject| so that this
operation does not need to iterate items, but this patch adds
a slow-but-simple version. The optimization will be in
following patches.

Bug: 982194
Change-Id: I91f2e85a98dffec47797f9cbe37af40e3c5cecd0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1768176
Auto-Submit: Koji Ishii <kojii@chromium.org>
Reviewed-by: default avatarEmil A Eklund <eae@chromium.org>
Commit-Queue: Koji Ishii <kojii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#690178}
parent b3259b9d
......@@ -66,4 +66,44 @@ IntRect NGFragmentItem::VisualRect() const {
return IntRect();
}
NGFragmentItem::ItemsForLayoutObject NGFragmentItem::ItemsFor(
const LayoutObject& layout_object) {
DCHECK(layout_object.IsInLayoutNGInlineFormattingContext());
DCHECK(layout_object.IsText() || layout_object.IsLayoutInline() ||
(layout_object.IsBox() && layout_object.IsInline()));
// TODO(kojii): This is a hot function needed by paint and several other
// operations. Make this fast, by not iterating.
if (const LayoutBlockFlow* block_flow =
layout_object.RootInlineFormattingContext()) {
if (const NGPhysicalBoxFragment* fragment = block_flow->CurrentFragment()) {
if (const NGFragmentItems* items = fragment->Items()) {
for (unsigned i = 0; i < items->Items().size(); ++i) {
const NGFragmentItem* item = items->Items()[i].get();
if (item->GetLayoutObject() == &layout_object)
return ItemsForLayoutObject(items->Items(), i, item);
}
}
}
}
return ItemsForLayoutObject();
}
NGFragmentItem::ItemsForLayoutObject::Iterator&
NGFragmentItem::ItemsForLayoutObject::Iterator::operator++() {
// TODO(kojii): This is a hot function needed by paint and several other
// operations. Make this fast, by not iterating.
if (!current_)
return *this;
const LayoutObject* current_layout_object = current_->GetLayoutObject();
while (++index_ < items_->size()) {
current_ = (*items_)[index_].get();
if (current_->GetLayoutObject() == current_layout_object)
return *this;
}
current_ = nullptr;
return *this;
}
} // namespace blink
......@@ -95,6 +95,53 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient {
String DebugName() const override;
IntRect VisualRect() const override;
// Find |NGFragmentItem|s that are associated with a |LayoutObject|.
class CORE_EXPORT ItemsForLayoutObject {
STACK_ALLOCATED();
public:
ItemsForLayoutObject() = default;
ItemsForLayoutObject(const Vector<std::unique_ptr<NGFragmentItem>>& items,
unsigned first_index,
const NGFragmentItem* first_item)
: items_(&items), first_item_(first_item), first_index_(first_index) {}
bool IsEmpty() const { return !items_; }
class CORE_EXPORT Iterator {
public:
Iterator(const Vector<std::unique_ptr<NGFragmentItem>>* items,
unsigned index,
const NGFragmentItem* item)
: current_(item), items_(items), index_(index) {}
const NGFragmentItem& operator*() const { return *current_; }
const NGFragmentItem& operator->() const { return *current_; }
Iterator& operator++();
bool operator==(const Iterator& other) const {
return current_ == other.current_;
}
bool operator!=(const Iterator& other) const {
return current_ != other.current_;
}
private:
const NGFragmentItem* current_;
const Vector<std::unique_ptr<NGFragmentItem>>* items_;
unsigned index_;
};
using iterator = Iterator;
iterator begin() const {
return Iterator(items_, first_index_, first_item_);
}
iterator end() const { return Iterator(nullptr, 0, nullptr); }
private:
const Vector<std::unique_ptr<NGFragmentItem>>* items_;
const NGFragmentItem* first_item_;
unsigned first_index_;
};
static ItemsForLayoutObject ItemsFor(const LayoutObject& layout_object);
// Painters can use const methods only, except for these explicitly declared
// methods.
class MutableForPainting {
......
......@@ -37,4 +37,34 @@ TEST_F(NGFragmentItemTest, Simple) {
EXPECT_NE(items, nullptr);
}
TEST_F(NGFragmentItemTest, ForLayoutObject) {
SetBodyInnerHTML(R"HTML(
<style>
#container {
font-family: monospace;
width: 5ch;
}
#span {
background: gray;
}
</style>
<div id="container">
0123
<span id="span">1234 5678</span>
6789
</div>
)HTML");
const LayoutObject* span = GetLayoutObjectByElementId("span");
ASSERT_NE(span, nullptr);
const auto items = NGFragmentItem::ItemsFor(*span);
EXPECT_FALSE(items.IsEmpty());
unsigned count = 0;
for (const NGFragmentItem& item : items) {
EXPECT_EQ(item.GetLayoutObject(), span);
++count;
}
EXPECT_EQ(count, 2u);
}
} // namespace blink
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