Commit 92ee7eb9 authored by Koji Ishii's avatar Koji Ishii Committed by Commit Bot

[FragmentItem] Add NGInlineCursor::CursorForDescendants()

This patch adds |NGInlineCursor::CursorForDescendants()|,
which returns an |NGInlineCursor| that traverses descendants
of the current item.

This is needed to compute ink overflow of an inline box (WIP:
crrev.com/c/1771360), but is likely to be needed in some
other places too.

Bug: 982194
Change-Id: I3432b3b73580f5b63591c7fc52c35e4b7e3576f6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1888868Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Commit-Queue: Koji Ishii <kojii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#710708}
parent 96eff6ba
...@@ -113,6 +113,7 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient { ...@@ -113,6 +113,7 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient {
return line_.descendants_count; return line_.descendants_count;
return 0; return 0;
} }
bool HasChildren() const { return DescendantsCount() > 1; }
// Returns |NGPhysicalBoxFragment| if one is associated with this item. // Returns |NGPhysicalBoxFragment| if one is associated with this item.
const NGPhysicalBoxFragment* BoxFragment() const { const NGPhysicalBoxFragment* BoxFragment() const {
......
...@@ -20,21 +20,22 @@ void NGInlineCursor::MoveToItem(const ItemsSpan::iterator& iter) { ...@@ -20,21 +20,22 @@ void NGInlineCursor::MoveToItem(const ItemsSpan::iterator& iter) {
current_item_ = iter == items_.end() ? nullptr : iter->get(); current_item_ = iter == items_.end() ? nullptr : iter->get();
} }
void NGInlineCursor::SetRoot(ItemsSpan items) { void NGInlineCursor::SetRoot(const NGFragmentItems& fragment_items,
ItemsSpan items) {
DCHECK(items.data() || !items.size()); DCHECK(items.data() || !items.size());
DCHECK_EQ(root_paint_fragment_, nullptr); DCHECK_EQ(root_paint_fragment_, nullptr);
DCHECK_EQ(current_paint_fragment_, nullptr); DCHECK_EQ(current_paint_fragment_, nullptr);
fragment_items_ = &fragment_items;
items_ = items; items_ = items;
MoveToItem(items_.begin()); MoveToItem(items_.begin());
} }
void NGInlineCursor::SetRoot(const NGFragmentItems& items) { void NGInlineCursor::SetRoot(const NGFragmentItems& items) {
SetRoot(items.Items()); SetRoot(items, items.Items());
} }
void NGInlineCursor::SetRoot(const NGPaintFragment& root_paint_fragment) { void NGInlineCursor::SetRoot(const NGPaintFragment& root_paint_fragment) {
DCHECK(&root_paint_fragment); DCHECK(&root_paint_fragment);
DCHECK(!root_paint_fragment.Parent()) << root_paint_fragment;
root_paint_fragment_ = &root_paint_fragment; root_paint_fragment_ = &root_paint_fragment;
current_paint_fragment_ = root_paint_fragment.FirstChild(); current_paint_fragment_ = root_paint_fragment.FirstChild();
} }
...@@ -60,8 +61,12 @@ NGInlineCursor::NGInlineCursor(const LayoutBlockFlow& block_flow) { ...@@ -60,8 +61,12 @@ NGInlineCursor::NGInlineCursor(const LayoutBlockFlow& block_flow) {
// See external/wpt/css/css-scroll-anchoring/wrapped-text.html // See external/wpt/css/css-scroll-anchoring/wrapped-text.html
} }
NGInlineCursor::NGInlineCursor(const NGFragmentItems& items) NGInlineCursor::NGInlineCursor(const NGFragmentItems& fragment_items,
: fragment_items_(&items) { ItemsSpan items) {
SetRoot(fragment_items, items);
}
NGInlineCursor::NGInlineCursor(const NGFragmentItems& items) {
SetRoot(items); SetRoot(items);
} }
...@@ -95,11 +100,21 @@ bool NGInlineCursor::operator==(const NGInlineCursor& other) const { ...@@ -95,11 +100,21 @@ bool NGInlineCursor::operator==(const NGInlineCursor& other) const {
} }
const LayoutBlockFlow* NGInlineCursor::GetLayoutBlockFlow() const { const LayoutBlockFlow* NGInlineCursor::GetLayoutBlockFlow() const {
if (root_paint_fragment_) if (IsPaintFragmentCursor()) {
return To<LayoutBlockFlow>(root_paint_fragment_->GetLayoutObject()); // |root_paint_fragment_| is either |LayoutBlockFlow| or |LayoutInline|.
for (const auto& item : items_) { const LayoutObject* layout_object = root_paint_fragment_->GetLayoutObject();
if (item->GetLayoutObject() && item->GetLayoutObject()->IsInline()) if (const LayoutBlockFlow* block_flow =
return item->GetLayoutObject()->RootInlineFormattingContext(); DynamicTo<LayoutBlockFlow>(layout_object))
return block_flow;
DCHECK(layout_object->IsLayoutInline());
return layout_object->RootInlineFormattingContext();
}
if (IsItemCursor()) {
for (const auto& item : items_) {
const LayoutObject* layout_object = item->GetLayoutObject();
if (layout_object && layout_object->IsInline())
return layout_object->RootInlineFormattingContext();
}
} }
NOTREACHED(); NOTREACHED();
return nullptr; return nullptr;
...@@ -108,12 +123,26 @@ const LayoutBlockFlow* NGInlineCursor::GetLayoutBlockFlow() const { ...@@ -108,12 +123,26 @@ const LayoutBlockFlow* NGInlineCursor::GetLayoutBlockFlow() const {
bool NGInlineCursor::HasChildren() const { bool NGInlineCursor::HasChildren() const {
if (current_paint_fragment_) if (current_paint_fragment_)
return current_paint_fragment_->FirstChild(); return current_paint_fragment_->FirstChild();
if (current_item_)
return current_item_->HasChildren();
NOTREACHED();
return false;
}
NGInlineCursor NGInlineCursor::CursorForDescendants() const {
if (current_paint_fragment_)
return NGInlineCursor(*current_paint_fragment_);
if (current_item_) { if (current_item_) {
// Note: |DescendantsCount() == 1| means box/line without children. unsigned descendants_count = current_item_->DescendantsCount();
return current_item_->DescendantsCount() > 1; if (descendants_count > 1) {
DCHECK(fragment_items_);
return NGInlineCursor(*fragment_items_, ItemsSpan(&*(item_iter_ + 1),
descendants_count - 1));
}
return NGInlineCursor();
} }
NOTREACHED(); NOTREACHED();
return false; return NGInlineCursor();
} }
bool NGInlineCursor::HasSoftWrapToNextLine() const { bool NGInlineCursor::HasSoftWrapToNextLine() const {
......
...@@ -39,8 +39,12 @@ class CORE_EXPORT NGInlineCursor { ...@@ -39,8 +39,12 @@ class CORE_EXPORT NGInlineCursor {
STACK_ALLOCATED(); STACK_ALLOCATED();
public: public:
using ItemsSpan = base::span<const std::unique_ptr<NGFragmentItem>>;
explicit NGInlineCursor(const LayoutBlockFlow& block_flow); explicit NGInlineCursor(const LayoutBlockFlow& block_flow);
explicit NGInlineCursor(const NGFragmentItems& items); explicit NGInlineCursor(const NGFragmentItems& items);
explicit NGInlineCursor(const NGFragmentItems& fragment_items,
ItemsSpan items);
explicit NGInlineCursor(const NGPaintFragment& root_paint_fragment); explicit NGInlineCursor(const NGPaintFragment& root_paint_fragment);
NGInlineCursor(const NGInlineCursor& other); NGInlineCursor(const NGInlineCursor& other);
NGInlineCursor(); NGInlineCursor();
...@@ -77,6 +81,11 @@ class CORE_EXPORT NGInlineCursor { ...@@ -77,6 +81,11 @@ class CORE_EXPORT NGInlineCursor {
// True if fragment at the current position has children. // True if fragment at the current position has children.
bool HasChildren() const; bool HasChildren() const;
// Returns a new |NGInlineCursor| whose root is the current item. The returned
// cursor can traverse descendants of the current item. If the current item
// has no children, returns an empty cursor.
NGInlineCursor CursorForDescendants() const;
// True if current position has soft wrap to next line. It is error to call // True if current position has soft wrap to next line. It is error to call
// other than line. // other than line.
bool HasSoftWrapToNextLine() const; bool HasSoftWrapToNextLine() const;
...@@ -229,8 +238,6 @@ class CORE_EXPORT NGInlineCursor { ...@@ -229,8 +238,6 @@ class CORE_EXPORT NGInlineCursor {
// NextSkippingChildren, Previous, etc. // NextSkippingChildren, Previous, etc.
private: private:
using ItemsSpan = base::span<const std::unique_ptr<NGFragmentItem>>;
// Returns break token for line box. It is error to call other than line box. // Returns break token for line box. It is error to call other than line box.
const NGInlineBreakToken& CurrentInlineBreakToken() const; const NGInlineBreakToken& CurrentInlineBreakToken() const;
...@@ -253,7 +260,7 @@ class CORE_EXPORT NGInlineCursor { ...@@ -253,7 +260,7 @@ class CORE_EXPORT NGInlineCursor {
void InternalMoveTo(const LayoutObject& layout_object); void InternalMoveTo(const LayoutObject& layout_object);
void SetRoot(const NGFragmentItems& items); void SetRoot(const NGFragmentItems& items);
void SetRoot(ItemsSpan items); void SetRoot(const NGFragmentItems& fragment_items, ItemsSpan items);
void SetRoot(const NGPaintFragment& root_paint_fragment); void SetRoot(const NGPaintFragment& root_paint_fragment);
void MoveToItem(const ItemsSpan::iterator& iter); void MoveToItem(const ItemsSpan::iterator& iter);
......
...@@ -409,4 +409,46 @@ TEST_P(NGInlineCursorTest, PreviousLine) { ...@@ -409,4 +409,46 @@ TEST_P(NGInlineCursorTest, PreviousLine) {
EXPECT_EQ(line1, should_be_line1); EXPECT_EQ(line1, should_be_line1);
} }
TEST_P(NGInlineCursorTest, CursorForDescendants) {
SetBodyInnerHTML(R"HTML(
<style>
span { background: yellow; }
</style>
<div id=root>
text1
<span id="span1">
text2
<span id="span2">
text3
</span>
text4
</span>
text5
<span id="span3">
text6
</span>
text7
</div>
)HTML");
LayoutBlockFlow* block_flow =
To<LayoutBlockFlow>(GetLayoutObjectByElementId("root"));
NGInlineCursor cursor(*block_flow);
EXPECT_TRUE(cursor.IsLineBox());
cursor.MoveToNext();
EXPECT_TRUE(cursor.IsText());
EXPECT_THAT(ToDebugStringList(cursor.CursorForDescendants()), ElementsAre());
cursor.MoveToNext();
EXPECT_EQ(ToDebugString(cursor), "#span1");
EXPECT_THAT(ToDebugStringList(cursor.CursorForDescendants()),
ElementsAre("text2", "#span2", "text3", "text4"));
cursor.MoveToNext();
EXPECT_EQ(ToDebugString(cursor), "text2");
EXPECT_THAT(ToDebugStringList(cursor.CursorForDescendants()), ElementsAre());
cursor.MoveToNext();
EXPECT_EQ(ToDebugString(cursor), "#span2");
EXPECT_THAT(ToDebugStringList(cursor.CursorForDescendants()),
ElementsAre("text3"));
}
} // namespace blink } // 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