Commit 1b05460e authored by Koji Ishii's avatar Koji Ishii Committed by Commit Bot

[FragmentItem] Initial implementation of hit testing

This patch implements hit-testing for when FragmentItem is
enabled. Existing logic for |NGPaintFragment| is abstracted
by using |NGInlineCursor|.

Hit-testing text items and culled inline boxes are not
implemented yet, I will work on in following patches.

~30 new failures, fixes ~740.

There should be no behavior changes unless FragmentItem
run-time flag is enabled.

Bug: 982194
Change-Id: I4b7ff6020f8d6edfb898ead65976ef6a276cce23
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1935773
Commit-Queue: Koji Ishii <kojii@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarXianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#720001}
parent fa202801
......@@ -1078,8 +1078,8 @@ void NGInlineCursor::MoveToPreviousSiblingPaintFragment() {
NOTREACHED();
}
NGInlineBackwardCursor::NGInlineBackwardCursor(const NGInlineCursor& cursor) {
DCHECK(cursor);
NGInlineBackwardCursor::NGInlineBackwardCursor(const NGInlineCursor& cursor)
: cursor_(cursor) {
if (cursor.root_paint_fragment_) {
for (NGInlineCursor sibling(cursor); sibling; sibling.MoveToNextSibling())
sibling_paint_fragments_.push_back(sibling.CurrentPaintFragment());
......@@ -1102,11 +1102,33 @@ NGInlineBackwardCursor::NGInlineBackwardCursor(const NGInlineCursor& cursor) {
NGInlineCursor NGInlineBackwardCursor::CursorForDescendants() const {
if (const NGPaintFragment* current_paint_fragment = CurrentPaintFragment())
return NGInlineCursor(*current_paint_fragment);
// TODO(kojii): Implement for items.
if (current_item_) {
NGInlineCursor cursor(cursor_);
cursor.MoveToItem(sibling_item_iterators_[current_index_]);
return cursor.CursorForDescendants();
}
NOTREACHED();
return NGInlineCursor();
}
const PhysicalOffset NGInlineBackwardCursor::CurrentOffset() const {
if (current_paint_fragment_)
return current_paint_fragment_->InlineOffsetToContainerBox();
if (current_item_)
return current_item_->Offset();
NOTREACHED();
return PhysicalOffset();
}
const PhysicalRect NGInlineBackwardCursor::CurrentSelfInkOverflow() const {
if (current_paint_fragment_)
return current_paint_fragment_->SelfInkOverflow();
if (current_item_)
return current_item_->SelfInkOverflow();
NOTREACHED();
return PhysicalRect();
}
void NGInlineBackwardCursor::MoveToPreviousSibling() {
if (current_index_) {
if (current_paint_fragment_) {
......
......@@ -364,6 +364,8 @@ class CORE_EXPORT NGInlineCursor {
friend class NGInlineBackwardCursor;
};
// This class provides the |MoveToPreviousSibling| functionality, but as a
// separate class because it consumes memory, and only rarely used.
class CORE_EXPORT NGInlineBackwardCursor {
STACK_ALLOCATED();
......@@ -381,9 +383,13 @@ class CORE_EXPORT NGInlineBackwardCursor {
return current_paint_fragment_;
}
const PhysicalOffset CurrentOffset() const;
const PhysicalRect CurrentSelfInkOverflow() const;
void MoveToPreviousSibling();
private:
const NGInlineCursor& cursor_;
Vector<const NGPaintFragment*, 16> sibling_paint_fragments_;
Vector<NGInlineCursor::ItemsSpan::iterator, 16> sibling_item_iterators_;
const NGPaintFragment* current_paint_fragment_ = nullptr;
......
......@@ -315,29 +315,37 @@ bool LayoutNGBlockFlowMixin<Base>::NodeAtPoint(
const HitTestLocation& hit_test_location,
const PhysicalOffset& accumulated_offset,
HitTestAction action) {
const NGPaintFragment* paint_fragment = PaintFragment();
if (!paint_fragment) {
return LayoutBlockFlow::NodeAtPoint(result, hit_test_location,
accumulated_offset, action);
if (const NGPaintFragment* paint_fragment = PaintFragment()) {
if (!this->IsEffectiveRootScroller()) {
// Check if we need to do anything at all.
// If we have clipping, then we can't have any spillout.
PhysicalRect overflow_box = Base::HasOverflowClip()
? Base::PhysicalBorderBoxRect()
: Base::PhysicalVisualOverflowRect();
overflow_box.Move(accumulated_offset);
if (!hit_test_location.Intersects(overflow_box))
return false;
}
if (Base::IsInSelfHitTestingPhase(action) && Base::HasOverflowClip() &&
Base::HitTestOverflowControl(result, hit_test_location,
accumulated_offset))
return true;
return NGBoxFragmentPainter(*paint_fragment)
.NodeAtPoint(result, hit_test_location, accumulated_offset, action);
}
if (!this->IsEffectiveRootScroller()) {
// Check if we need to do anything at all.
// If we have clipping, then we can't have any spillout.
PhysicalRect overflow_box = Base::HasOverflowClip()
? Base::PhysicalBorderBoxRect()
: Base::PhysicalVisualOverflowRect();
overflow_box.Move(accumulated_offset);
if (!hit_test_location.Intersects(overflow_box))
return false;
if (UNLIKELY(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())) {
if (const NGPhysicalBoxFragment* fragment = CurrentFragment()) {
if (fragment->HasItems()) {
return NGBoxFragmentPainter(*fragment).NodeAtPoint(
result, hit_test_location, accumulated_offset, action);
}
}
}
if (Base::IsInSelfHitTestingPhase(action) && Base::HasOverflowClip() &&
Base::HitTestOverflowControl(result, hit_test_location,
accumulated_offset))
return true;
return NGBoxFragmentPainter(*paint_fragment)
.NodeAtPoint(result, hit_test_location, accumulated_offset, action);
return LayoutBlockFlow::NodeAtPoint(result, hit_test_location,
accumulated_offset, action);
}
template <typename Base>
......
......@@ -23,6 +23,7 @@ class HitTestRequest;
class HitTestResult;
class NGFragmentItems;
class NGInlineCursor;
class NGInlineBackwardCursor;
class NGPhysicalFragment;
class ScopedPaintState;
struct PaintInfo;
......@@ -37,6 +38,9 @@ class NGBoxFragmentPainter : public BoxPainterBase {
const NGPaintFragment* = nullptr,
NGInlineCursor* descendants = nullptr);
NGBoxFragmentPainter(const NGPaintFragment&);
NGBoxFragmentPainter(const NGPhysicalBoxFragment& fragment,
NGInlineCursor* descendants)
: NGBoxFragmentPainter(fragment, nullptr, descendants) {}
void Paint(const PaintInfo&);
void PaintObject(const PaintInfo&,
......@@ -153,17 +157,32 @@ class NGBoxFragmentPainter : public BoxPainterBase {
// box in paint layer. Note that this includes scrolling offset when the
// container has 'overflow: scroll'.
bool HitTestChildren(HitTestResult&,
NGPaintFragment::ChildList,
const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset,
HitTestAction);
bool HitTestChildren(HitTestResult&,
const NGInlineCursor& children,
const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset,
HitTestAction);
bool HitTestPaintFragmentChildren(HitTestResult&,
const NGInlineCursor& children,
const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset,
HitTestAction);
bool HitTestItemsChildren(HitTestResult&,
const NGInlineCursor& children,
const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset,
HitTestAction);
// Hit tests a box fragment, which is a child of either |box_fragment_|, or
// one of its child line box fragments.
// @param physical_offset Physical offset of the given box fragment in the
// paint layer.
bool HitTestChildBoxFragment(HitTestResult&,
const NGPaintFragment&,
const NGPhysicalBoxFragment& fragment,
const NGInlineBackwardCursor& cursor,
const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset,
HitTestAction);
......@@ -171,7 +190,7 @@ class NGBoxFragmentPainter : public BoxPainterBase {
// Hit tests the given text fragment.
// @param physical_offset Physical offset of the text fragment in paint layer.
bool HitTestTextFragment(HitTestResult&,
const NGPaintFragment&,
const NGInlineBackwardCursor& cursor,
const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset,
HitTestAction);
......@@ -180,7 +199,8 @@ class NGBoxFragmentPainter : public BoxPainterBase {
// @param physical_offset Physical offset of the line box fragment in paint
// layer.
bool HitTestLineBoxFragment(HitTestResult&,
const NGPaintFragment&,
const NGPhysicalLineBoxFragment& fragment,
const NGInlineBackwardCursor& cursor,
const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset,
HitTestAction);
......@@ -221,6 +241,7 @@ inline NGBoxFragmentPainter::NGBoxFragmentPainter(
items_(box.Items()),
descendants_(descendants) {
DCHECK(box.IsBox() || box.IsRenderedLegend());
DCHECK(!paint_fragment || !descendants);
#if DCHECK_IS_ON()
if (box.IsInlineBox()) {
if (paint_fragment)
......
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