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

[FragmentItem] Block fragmentation support in NGInlineCursor

This patch adds block fragmentation functions to
|NGInlineCursor|, as detailed in the design doc:
https://docs.google.com/document/d/1mb_QRS67JQcOZ7oFdDb6UX-gx10IvhLwVPytNLM6wr0/edit?usp=sharing

The implementation is to traverses all fragments, which is
probably not fast enough to ship, but the behavior should
be correct. The performance work will be in future patches.

We can start removing work arounds such as ones in
|NGFragmentItems::LayoutObjectWillBeDestroyed|. Such work
will also be in future patches.

Bug: 829028, 982194, 1104064, 1112657
Change-Id: Ied6fb7b868895669c651418134041a0feda3c0d7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2313736
Commit-Queue: Koji Ishii <kojii@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarMorten Stenshorne <mstensho@chromium.org>
Cr-Commit-Position: refs/heads/master@{#795011}
parent 36039818
...@@ -413,6 +413,28 @@ class CORE_EXPORT NGInlineCursor { ...@@ -413,6 +413,28 @@ class CORE_EXPORT NGInlineCursor {
// Returns true if the current position moves to last child. // Returns true if the current position moves to last child.
bool TryToMoveToLastChild(); bool TryToMoveToLastChild();
//
// Moving across fragmentainers.
//
// When rooted at |LayoutBlockFlow|, |this| can move the current position
// across fragmentainers. Other root objects (e.g. |NGFragmentItems|) can
// contain only one fragmentainer that such cursors cannot move to different
// fragmentainers. See |CanMoveAcrossFragmentainer()|.
//
// However, |MoveToNext| etc. does not move the current position across
// fragmentainers. Use following functions when moving to different
// fragmentainers.
// Move to the first item of the first fragmentainer.
void MoveToFirstIncludingFragmentainer();
// Move to the next fragmentainer. Valid when |CanMoveAcrossFragmentainer|.
void MoveToNextFragmentainer();
// Same as |MoveToNext|, except this moves to the next fragmentainer if
// |Current| is at the end of a fragmentainer.
void MoveToNextIncludingFragmentainer();
// //
// Functions to enumerate fragments for a |LayoutObject|. // Functions to enumerate fragments for a |LayoutObject|.
// //
...@@ -451,11 +473,19 @@ class CORE_EXPORT NGInlineCursor { ...@@ -451,11 +473,19 @@ class CORE_EXPORT NGInlineCursor {
return root_paint_fragment_->Parent(); return root_paint_fragment_->Parent();
return false; return false;
} }
bool CanMoveAcrossFragmentainer() const {
return root_block_flow_ && IsItemCursor() && !IsDescendantsCursor();
}
bool CanUseLayoutObjectIndex() const;
// True if the current position is a last line in inline block. It is error // True if the current position is a last line in inline block. It is error
// to call at end or the current position is not line. // to call at end or the current position is not line.
bool IsLastLineInInlineBlock() const; bool IsLastLineInInlineBlock() const;
// Index conversions for |IsDescendantsCursor()|.
wtf_size_t SpanBeginItemIndex() const;
wtf_size_t SpanIndexFromItemIndex(unsigned index) const;
// Make the current position points nothing, e.g. cursor moves over start/end // Make the current position points nothing, e.g. cursor moves over start/end
// fragment, cursor moves to first/last child to parent has no children. // fragment, cursor moves to first/last child to parent has no children.
void MakeNull() { current_.Clear(); } void MakeNull() { current_.Clear(); }
...@@ -467,6 +497,9 @@ class CORE_EXPORT NGInlineCursor { ...@@ -467,6 +497,9 @@ class CORE_EXPORT NGInlineCursor {
void SetRoot(const NGFragmentItems& fragment_items, 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 SetRoot(const LayoutBlockFlow& block_flow); void SetRoot(const LayoutBlockFlow& block_flow);
bool SetRoot(const LayoutBlockFlow& block_flow, wtf_size_t fragment_index);
bool TrySetRootFragmentItems();
void MoveToItem(const ItemsSpan::iterator& iter); void MoveToItem(const ItemsSpan::iterator& iter);
void MoveToNextItem(); void MoveToNextItem();
...@@ -480,13 +513,9 @@ class CORE_EXPORT NGInlineCursor { ...@@ -480,13 +513,9 @@ class CORE_EXPORT NGInlineCursor {
void MoveToPreviousPaintFragment(); void MoveToPreviousPaintFragment();
void MoveToPreviousSiblingPaintFragment(); void MoveToPreviousSiblingPaintFragment();
static ItemsSpan::iterator SlowFirstItemIteratorFor( void SlowMoveToFirstFor(const LayoutObject& layout_object);
const LayoutObject& layout_object, void SlowMoveToNextForSameLayoutObject(const LayoutObject& layout_object);
const ItemsSpan& items); void SlowMoveToForIfNeeded(const LayoutObject& layout_object);
static wtf_size_t SlowFirstItemIndexFor(const LayoutObject& layout_object,
const ItemsSpan& items);
wtf_size_t SpanBeginItemIndex() const;
wtf_size_t SpanIndexFromItemIndex(unsigned index) const;
// |MoveToNextForSameLayoutObject| that doesn't check |culled_inline_|. // |MoveToNextForSameLayoutObject| that doesn't check |culled_inline_|.
void MoveToNextForSameLayoutObjectExceptCulledInline(); void MoveToNextForSameLayoutObjectExceptCulledInline();
...@@ -507,7 +536,7 @@ class CORE_EXPORT NGInlineCursor { ...@@ -507,7 +536,7 @@ class CORE_EXPORT NGInlineCursor {
const LayoutObject* MoveToNext(); const LayoutObject* MoveToNext();
private: private:
const LayoutObject* SetCurrent(const LayoutObject* child); const LayoutObject* Find(const LayoutObject* child) const;
const LayoutObject* current_object_ = nullptr; const LayoutObject* current_object_ = nullptr;
const LayoutInline* layout_inline_ = nullptr; const LayoutInline* layout_inline_ = nullptr;
...@@ -526,6 +555,14 @@ class CORE_EXPORT NGInlineCursor { ...@@ -526,6 +555,14 @@ class CORE_EXPORT NGInlineCursor {
CulledInlineTraversal culled_inline_; CulledInlineTraversal culled_inline_;
// Used to traverse multiple |NGFragmentItems| when block fragmented.
const LayoutBlockFlow* root_block_flow_ = nullptr;
wtf_size_t fragment_index_ = 0;
wtf_size_t max_fragment_index_ = 0;
// Used only when |!CanUseLayoutObjectIndex|.
const LayoutObject* layout_object_to_slow_move_to_ = nullptr;
friend class NGInlineBackwardCursor; friend class NGInlineBackwardCursor;
}; };
......
...@@ -1056,6 +1056,124 @@ TEST_P(NGInlineCursorTest, CursorForDescendants) { ...@@ -1056,6 +1056,124 @@ TEST_P(NGInlineCursorTest, CursorForDescendants) {
ElementsAre("text3")); ElementsAre("text3"));
} }
class NGInlineCursorBlockFragmentationTest
: public NGLayoutTest,
private ScopedLayoutNGBlockFragmentationForTest {
public:
NGInlineCursorBlockFragmentationTest()
: ScopedLayoutNGBlockFragmentationForTest(true) {}
};
TEST_F(NGInlineCursorBlockFragmentationTest, MoveToLayoutObject) {
// This creates 3 columns, 1 line in each column.
SetBodyInnerHTML(R"HTML(
<style>
#container {
column-width: 6ch;
font-family: monospace;
font-size: 10px;
height: 1.5em;
}
</style>
<div id="container">
<span id="span1">1111 22</span><span id="span2">33 4444</span>
</div>
)HTML");
const LayoutObject* span1 = GetLayoutObjectByElementId("span1");
const LayoutObject* text1 = span1->SlowFirstChild();
const LayoutObject* span2 = GetLayoutObjectByElementId("span2");
const LayoutObject* text2 = span2->SlowFirstChild();
// Enumerate all fragments for |LayoutText|.
{
NGInlineCursor cursor;
cursor.MoveTo(*text1);
EXPECT_THAT(LayoutObjectToDebugStringList(cursor),
ElementsAre("1111", "22"));
}
{
NGInlineCursor cursor;
cursor.MoveTo(*text2);
EXPECT_THAT(LayoutObjectToDebugStringList(cursor),
ElementsAre("33", "4444"));
}
// |MoveTo| can find no fragments for culled inline.
{
NGInlineCursor cursor;
cursor.MoveTo(*span1);
EXPECT_FALSE(cursor);
}
{
NGInlineCursor cursor;
cursor.MoveTo(*span2);
EXPECT_FALSE(cursor);
}
// But |MoveToIncludingCulledInline| should find its descendants.
{
NGInlineCursor cursor;
cursor.MoveToIncludingCulledInline(*span1);
EXPECT_THAT(LayoutObjectToDebugStringList(cursor),
ElementsAre("1111", "22"));
}
{
NGInlineCursor cursor;
cursor.MoveToIncludingCulledInline(*span2);
EXPECT_THAT(LayoutObjectToDebugStringList(cursor),
ElementsAre("33", "4444"));
}
// Line-ranged cursors can find fragments only in the line.
// The 1st line has "1111", from "text1".
NGInlineCursor cursor(*span1->FragmentItemsContainer());
EXPECT_TRUE(cursor.Current().IsLineBox());
NGInlineCursor line1 = cursor.CursorForDescendants();
line1.MoveTo(*text1);
EXPECT_THAT(LayoutObjectToDebugStringList(line1), ElementsAre("1111"));
line1 = cursor.CursorForDescendants();
line1.MoveToIncludingCulledInline(*span1);
EXPECT_THAT(LayoutObjectToDebugStringList(line1), ElementsAre("1111"));
line1 = cursor.CursorForDescendants();
line1.MoveTo(*text2);
EXPECT_THAT(LayoutObjectToDebugStringList(line1), ElementsAre());
line1 = cursor.CursorForDescendants();
line1.MoveToIncludingCulledInline(*span2);
EXPECT_THAT(LayoutObjectToDebugStringList(line1), ElementsAre());
// The 2nd line has "22" from "text1" and "33" from text2.
cursor.MoveToNextFragmentainer();
EXPECT_TRUE(cursor);
EXPECT_TRUE(cursor.Current().IsLineBox());
NGInlineCursor line2 = cursor.CursorForDescendants();
line2.MoveTo(*text1);
EXPECT_THAT(LayoutObjectToDebugStringList(line2), ElementsAre("22"));
line2 = cursor.CursorForDescendants();
line2.MoveToIncludingCulledInline(*span1);
EXPECT_THAT(LayoutObjectToDebugStringList(line2), ElementsAre("22"));
line2 = cursor.CursorForDescendants();
line2.MoveTo(*text2);
EXPECT_THAT(LayoutObjectToDebugStringList(line2), ElementsAre("33"));
line2 = cursor.CursorForDescendants();
line2.MoveToIncludingCulledInline(*span2);
EXPECT_THAT(LayoutObjectToDebugStringList(line2), ElementsAre("33"));
// The 3rd line has "4444" from text2.
cursor.MoveToNextFragmentainer();
EXPECT_TRUE(cursor);
EXPECT_TRUE(cursor.Current().IsLineBox());
NGInlineCursor line3 = cursor.CursorForDescendants();
line3.MoveTo(*text1);
EXPECT_THAT(LayoutObjectToDebugStringList(line3), ElementsAre());
line3 = cursor.CursorForDescendants();
line3.MoveToIncludingCulledInline(*span1);
EXPECT_THAT(LayoutObjectToDebugStringList(line3), ElementsAre());
line3 = cursor.CursorForDescendants();
line3.MoveTo(*text2);
EXPECT_THAT(LayoutObjectToDebugStringList(line3), ElementsAre("4444"));
line3 = cursor.CursorForDescendants();
line3.MoveToIncludingCulledInline(*span2);
EXPECT_THAT(LayoutObjectToDebugStringList(line3), ElementsAre("4444"));
}
} // namespace } // namespace
} // 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