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() { ...@@ -1078,8 +1078,8 @@ void NGInlineCursor::MoveToPreviousSiblingPaintFragment() {
NOTREACHED(); NOTREACHED();
} }
NGInlineBackwardCursor::NGInlineBackwardCursor(const NGInlineCursor& cursor) { NGInlineBackwardCursor::NGInlineBackwardCursor(const NGInlineCursor& cursor)
DCHECK(cursor); : cursor_(cursor) {
if (cursor.root_paint_fragment_) { if (cursor.root_paint_fragment_) {
for (NGInlineCursor sibling(cursor); sibling; sibling.MoveToNextSibling()) for (NGInlineCursor sibling(cursor); sibling; sibling.MoveToNextSibling())
sibling_paint_fragments_.push_back(sibling.CurrentPaintFragment()); sibling_paint_fragments_.push_back(sibling.CurrentPaintFragment());
...@@ -1102,11 +1102,33 @@ NGInlineBackwardCursor::NGInlineBackwardCursor(const NGInlineCursor& cursor) { ...@@ -1102,11 +1102,33 @@ NGInlineBackwardCursor::NGInlineBackwardCursor(const NGInlineCursor& cursor) {
NGInlineCursor NGInlineBackwardCursor::CursorForDescendants() const { NGInlineCursor NGInlineBackwardCursor::CursorForDescendants() const {
if (const NGPaintFragment* current_paint_fragment = CurrentPaintFragment()) if (const NGPaintFragment* current_paint_fragment = CurrentPaintFragment())
return NGInlineCursor(*current_paint_fragment); 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(); NOTREACHED();
return NGInlineCursor(); 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() { void NGInlineBackwardCursor::MoveToPreviousSibling() {
if (current_index_) { if (current_index_) {
if (current_paint_fragment_) { if (current_paint_fragment_) {
......
...@@ -364,6 +364,8 @@ class CORE_EXPORT NGInlineCursor { ...@@ -364,6 +364,8 @@ class CORE_EXPORT NGInlineCursor {
friend class NGInlineBackwardCursor; 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 { class CORE_EXPORT NGInlineBackwardCursor {
STACK_ALLOCATED(); STACK_ALLOCATED();
...@@ -381,9 +383,13 @@ class CORE_EXPORT NGInlineBackwardCursor { ...@@ -381,9 +383,13 @@ class CORE_EXPORT NGInlineBackwardCursor {
return current_paint_fragment_; return current_paint_fragment_;
} }
const PhysicalOffset CurrentOffset() const;
const PhysicalRect CurrentSelfInkOverflow() const;
void MoveToPreviousSibling(); void MoveToPreviousSibling();
private: private:
const NGInlineCursor& cursor_;
Vector<const NGPaintFragment*, 16> sibling_paint_fragments_; Vector<const NGPaintFragment*, 16> sibling_paint_fragments_;
Vector<NGInlineCursor::ItemsSpan::iterator, 16> sibling_item_iterators_; Vector<NGInlineCursor::ItemsSpan::iterator, 16> sibling_item_iterators_;
const NGPaintFragment* current_paint_fragment_ = nullptr; const NGPaintFragment* current_paint_fragment_ = nullptr;
......
...@@ -315,29 +315,37 @@ bool LayoutNGBlockFlowMixin<Base>::NodeAtPoint( ...@@ -315,29 +315,37 @@ bool LayoutNGBlockFlowMixin<Base>::NodeAtPoint(
const HitTestLocation& hit_test_location, const HitTestLocation& hit_test_location,
const PhysicalOffset& accumulated_offset, const PhysicalOffset& accumulated_offset,
HitTestAction action) { HitTestAction action) {
const NGPaintFragment* paint_fragment = PaintFragment(); if (const NGPaintFragment* paint_fragment = PaintFragment()) {
if (!paint_fragment) { if (!this->IsEffectiveRootScroller()) {
return LayoutBlockFlow::NodeAtPoint(result, hit_test_location, // Check if we need to do anything at all.
accumulated_offset, action); // 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()) { if (UNLIKELY(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())) {
// Check if we need to do anything at all. if (const NGPhysicalBoxFragment* fragment = CurrentFragment()) {
// If we have clipping, then we can't have any spillout. if (fragment->HasItems()) {
PhysicalRect overflow_box = Base::HasOverflowClip() return NGBoxFragmentPainter(*fragment).NodeAtPoint(
? Base::PhysicalBorderBoxRect() result, hit_test_location, accumulated_offset, action);
: 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) return LayoutBlockFlow::NodeAtPoint(result, hit_test_location,
.NodeAtPoint(result, hit_test_location, accumulated_offset, action); accumulated_offset, action);
} }
template <typename Base> template <typename Base>
......
...@@ -23,6 +23,7 @@ class HitTestRequest; ...@@ -23,6 +23,7 @@ class HitTestRequest;
class HitTestResult; class HitTestResult;
class NGFragmentItems; class NGFragmentItems;
class NGInlineCursor; class NGInlineCursor;
class NGInlineBackwardCursor;
class NGPhysicalFragment; class NGPhysicalFragment;
class ScopedPaintState; class ScopedPaintState;
struct PaintInfo; struct PaintInfo;
...@@ -37,6 +38,9 @@ class NGBoxFragmentPainter : public BoxPainterBase { ...@@ -37,6 +38,9 @@ class NGBoxFragmentPainter : public BoxPainterBase {
const NGPaintFragment* = nullptr, const NGPaintFragment* = nullptr,
NGInlineCursor* descendants = nullptr); NGInlineCursor* descendants = nullptr);
NGBoxFragmentPainter(const NGPaintFragment&); NGBoxFragmentPainter(const NGPaintFragment&);
NGBoxFragmentPainter(const NGPhysicalBoxFragment& fragment,
NGInlineCursor* descendants)
: NGBoxFragmentPainter(fragment, nullptr, descendants) {}
void Paint(const PaintInfo&); void Paint(const PaintInfo&);
void PaintObject(const PaintInfo&, void PaintObject(const PaintInfo&,
...@@ -153,17 +157,32 @@ class NGBoxFragmentPainter : public BoxPainterBase { ...@@ -153,17 +157,32 @@ class NGBoxFragmentPainter : public BoxPainterBase {
// box in paint layer. Note that this includes scrolling offset when the // box in paint layer. Note that this includes scrolling offset when the
// container has 'overflow: scroll'. // container has 'overflow: scroll'.
bool HitTestChildren(HitTestResult&, bool HitTestChildren(HitTestResult&,
NGPaintFragment::ChildList,
const HitTestLocation& hit_test_location, const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset, const PhysicalOffset& physical_offset,
HitTestAction); 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 // Hit tests a box fragment, which is a child of either |box_fragment_|, or
// one of its child line box fragments. // one of its child line box fragments.
// @param physical_offset Physical offset of the given box fragment in the // @param physical_offset Physical offset of the given box fragment in the
// paint layer. // paint layer.
bool HitTestChildBoxFragment(HitTestResult&, bool HitTestChildBoxFragment(HitTestResult&,
const NGPaintFragment&, const NGPhysicalBoxFragment& fragment,
const NGInlineBackwardCursor& cursor,
const HitTestLocation& hit_test_location, const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset, const PhysicalOffset& physical_offset,
HitTestAction); HitTestAction);
...@@ -171,7 +190,7 @@ class NGBoxFragmentPainter : public BoxPainterBase { ...@@ -171,7 +190,7 @@ class NGBoxFragmentPainter : public BoxPainterBase {
// Hit tests the given text fragment. // Hit tests the given text fragment.
// @param physical_offset Physical offset of the text fragment in paint layer. // @param physical_offset Physical offset of the text fragment in paint layer.
bool HitTestTextFragment(HitTestResult&, bool HitTestTextFragment(HitTestResult&,
const NGPaintFragment&, const NGInlineBackwardCursor& cursor,
const HitTestLocation& hit_test_location, const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset, const PhysicalOffset& physical_offset,
HitTestAction); HitTestAction);
...@@ -180,7 +199,8 @@ class NGBoxFragmentPainter : public BoxPainterBase { ...@@ -180,7 +199,8 @@ class NGBoxFragmentPainter : public BoxPainterBase {
// @param physical_offset Physical offset of the line box fragment in paint // @param physical_offset Physical offset of the line box fragment in paint
// layer. // layer.
bool HitTestLineBoxFragment(HitTestResult&, bool HitTestLineBoxFragment(HitTestResult&,
const NGPaintFragment&, const NGPhysicalLineBoxFragment& fragment,
const NGInlineBackwardCursor& cursor,
const HitTestLocation& hit_test_location, const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset, const PhysicalOffset& physical_offset,
HitTestAction); HitTestAction);
...@@ -221,6 +241,7 @@ inline NGBoxFragmentPainter::NGBoxFragmentPainter( ...@@ -221,6 +241,7 @@ inline NGBoxFragmentPainter::NGBoxFragmentPainter(
items_(box.Items()), items_(box.Items()),
descendants_(descendants) { descendants_(descendants) {
DCHECK(box.IsBox() || box.IsRenderedLegend()); DCHECK(box.IsBox() || box.IsRenderedLegend());
DCHECK(!paint_fragment || !descendants);
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
if (box.IsInlineBox()) { if (box.IsInlineBox()) {
if (paint_fragment) 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