Commit 9baf3afa authored by Koji Ishii's avatar Koji Ishii Committed by Commit Bot

[FragmentItem] Fix inline offset in hit-testing

This patch fixes inline offset in hit-testing when
|FragmentItem| is enabled.

|NGPaintFragment| has two kinds of offsets; one to the
parent, another to the containing block. |FragmentItem|
reduces this only to the containing block, the same as the
legacy |InlineBox|.

The hit-testing in |NGBoxFragmentPainter| uses the offsets
to the parent, and that part needs to change to support
|FragmentItem|.

Hit-testing functions in |NGBoxFragmentPainter| already
carry 3 arguments that do not change. Instead of adding the
4th argument that does not change, this patch adds
|HitTestContext| and pass it by reference.

7 failures, ~180 passes.

Bug: 982194
Change-Id: I840b0b3c63b2b1b58f10c8bf493e473d988ae0ac
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1954980
Commit-Queue: Koji Ishii <kojii@chromium.org>
Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#723029}
parent 97bc32e8
...@@ -1443,11 +1443,17 @@ bool NGBoxFragmentPainter::NodeAtPoint(HitTestResult& result, ...@@ -1443,11 +1443,17 @@ bool NGBoxFragmentPainter::NodeAtPoint(HitTestResult& result,
const HitTestLocation& hit_test_location, const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset, const PhysicalOffset& physical_offset,
HitTestAction action) { HitTestAction action) {
HitTestContext hit_test(action, hit_test_location, physical_offset, &result);
return NodeAtPoint(hit_test, physical_offset);
}
bool NGBoxFragmentPainter::NodeAtPoint(const HitTestContext& hit_test,
const PhysicalOffset& physical_offset) {
const NGPhysicalBoxFragment& fragment = PhysicalFragment(); const NGPhysicalBoxFragment& fragment = PhysicalFragment();
const PhysicalSize& size = box_fragment_.Size(); const PhysicalSize& size = box_fragment_.Size();
const ComputedStyle& style = box_fragment_.Style(); const ComputedStyle& style = box_fragment_.Style();
bool hit_test_self = IsInSelfHitTestingPhase(action); bool hit_test_self = IsInSelfHitTestingPhase(hit_test.action);
// TODO(layout-dev): Add support for hit testing overflow controls once we // TODO(layout-dev): Add support for hit testing overflow controls once we
// overflow has been implemented. // overflow has been implemented.
...@@ -1455,20 +1461,20 @@ bool NGBoxFragmentPainter::NodeAtPoint(HitTestResult& result, ...@@ -1455,20 +1461,20 @@ bool NGBoxFragmentPainter::NodeAtPoint(HitTestResult& result,
// HitTestOverflowControl(result, hit_test_location, physical_offset)) // HitTestOverflowControl(result, hit_test_location, physical_offset))
// return true; // return true;
bool skip_children = result.GetHitTestRequest().GetStopNode() == bool skip_children = hit_test.result->GetHitTestRequest().GetStopNode() ==
PhysicalFragment().GetLayoutObject(); PhysicalFragment().GetLayoutObject();
if (!skip_children && box_fragment_.ShouldClipOverflow()) { if (!skip_children && box_fragment_.ShouldClipOverflow()) {
// PaintLayer::HitTestContentsForFragments checked the fragments' // PaintLayer::HitTestContentsForFragments checked the fragments'
// foreground rect for intersection if a layer is self painting, // foreground rect for intersection if a layer is self painting,
// so only do the overflow clip check here for non-self-painting layers. // so only do the overflow clip check here for non-self-painting layers.
if (!box_fragment_.HasSelfPaintingLayer() && if (!box_fragment_.HasSelfPaintingLayer() &&
!hit_test_location.Intersects(PhysicalFragment().OverflowClipRect( !hit_test.location.Intersects(PhysicalFragment().OverflowClipRect(
physical_offset, kExcludeOverlayScrollbarSizeForHitTesting))) { physical_offset, kExcludeOverlayScrollbarSizeForHitTesting))) {
skip_children = true; skip_children = true;
} }
if (!skip_children && style.HasBorderRadius()) { if (!skip_children && style.HasBorderRadius()) {
PhysicalRect bounds_rect(physical_offset, size); PhysicalRect bounds_rect(physical_offset, size);
skip_children = !hit_test_location.Intersects( skip_children = !hit_test.location.Intersects(
style.GetRoundedInnerBorderFor(bounds_rect.ToLayoutRect())); style.GetRoundedInnerBorderFor(bounds_rect.ToLayoutRect()));
} }
} }
...@@ -1479,18 +1485,19 @@ bool NGBoxFragmentPainter::NodeAtPoint(HitTestResult& result, ...@@ -1479,18 +1485,19 @@ bool NGBoxFragmentPainter::NodeAtPoint(HitTestResult& result,
scrolled_offset -= PhysicalOffset( scrolled_offset -= PhysicalOffset(
PhysicalFragment().PixelSnappedScrolledContentOffset()); PhysicalFragment().PixelSnappedScrolledContentOffset());
} }
if (HitTestChildren(result, hit_test_location, scrolled_offset, action)) if (HitTestChildren(hit_test, scrolled_offset))
return true; return true;
} }
if (style.HasBorderRadius() && if (style.HasBorderRadius() &&
HitTestClippedOutByBorder(hit_test_location, physical_offset)) HitTestClippedOutByBorder(hit_test.location, physical_offset))
return false; return false;
// Now hit test ourselves. // Now hit test ourselves.
if (hit_test_self && VisibleToHitTestRequest(result.GetHitTestRequest())) { if (hit_test_self &&
VisibleToHitTestRequest(hit_test.result->GetHitTestRequest())) {
PhysicalRect bounds_rect(physical_offset, size); PhysicalRect bounds_rect(physical_offset, size);
if (UNLIKELY(result.GetHitTestRequest().GetType() & if (UNLIKELY(hit_test.result->GetHitTestRequest().GetType() &
HitTestRequest::kHitTestVisualOverflow)) { HitTestRequest::kHitTestVisualOverflow)) {
bounds_rect = paint_fragment_->SelfInkOverflow(); bounds_rect = paint_fragment_->SelfInkOverflow();
bounds_rect.Move(physical_offset); bounds_rect.Move(physical_offset);
...@@ -1499,14 +1506,14 @@ bool NGBoxFragmentPainter::NodeAtPoint(HitTestResult& result, ...@@ -1499,14 +1506,14 @@ bool NGBoxFragmentPainter::NodeAtPoint(HitTestResult& result,
// snap, but matches to legacy and fixes crbug.com/976606. // snap, but matches to legacy and fixes crbug.com/976606.
if (fragment.IsInlineBox()) if (fragment.IsInlineBox())
bounds_rect = PhysicalRect(PixelSnappedIntRect(bounds_rect)); bounds_rect = PhysicalRect(PixelSnappedIntRect(bounds_rect));
if (hit_test_location.Intersects(bounds_rect)) { if (hit_test.location.Intersects(bounds_rect)) {
Node* node = fragment.NodeForHitTest(); Node* node = fragment.NodeForHitTest();
if (!result.InnerNode() && node) { if (!hit_test.result->InnerNode() && node) {
PhysicalOffset point = hit_test_location.Point() - physical_offset; PhysicalOffset point = hit_test.location.Point() - physical_offset;
result.SetNodeAndPosition(node, point); hit_test.result->SetNodeAndPosition(node, point);
} }
if (result.AddNodeToListBasedTestResult(node, hit_test_location, if (hit_test.result->AddNodeToListBasedTestResult(
bounds_rect) == kStopHitTesting) { node, hit_test.location, bounds_rect) == kStopHitTesting) {
return true; return true;
} }
} }
...@@ -1521,119 +1528,104 @@ bool NGBoxFragmentPainter::VisibleToHitTestRequest( ...@@ -1521,119 +1528,104 @@ bool NGBoxFragmentPainter::VisibleToHitTestRequest(
} }
bool NGBoxFragmentPainter::HitTestTextFragment( bool NGBoxFragmentPainter::HitTestTextFragment(
HitTestResult& result, const HitTestContext& hit_test,
const NGInlineBackwardCursor& cursor, const NGInlineBackwardCursor& cursor,
const HitTestLocation& hit_test_location, const PhysicalOffset& physical_offset) {
const PhysicalOffset& physical_offset, if (hit_test.action != kHitTestForeground)
HitTestAction action) {
if (action != kHitTestForeground)
return false; return false;
const NGPaintFragment* text_paint_fragment = cursor.CurrentPaintFragment(); const NGPaintFragment* text_paint_fragment = cursor.CurrentPaintFragment();
DCHECK(text_paint_fragment); DCHECK(text_paint_fragment);
const auto& text_fragment = const auto& text_fragment =
To<NGPhysicalTextFragment>(text_paint_fragment->PhysicalFragment()); To<NGPhysicalTextFragment>(text_paint_fragment->PhysicalFragment());
PhysicalRect border_rect(physical_offset, text_fragment.Size()); if (!FragmentVisibleToHitTestRequest(text_fragment,
hit_test.result->GetHitTestRequest()))
return false;
// TODO(layout-dev): Clip to line-top/bottom. // TODO(layout-dev): Clip to line-top/bottom.
PhysicalRect border_rect(physical_offset, text_fragment.Size());
PhysicalRect rect(PixelSnappedIntRect(border_rect)); PhysicalRect rect(PixelSnappedIntRect(border_rect));
if (UNLIKELY(result.GetHitTestRequest().GetType() & if (UNLIKELY(hit_test.result->GetHitTestRequest().GetType() &
HitTestRequest::kHitTestVisualOverflow)) { HitTestRequest::kHitTestVisualOverflow)) {
rect = text_fragment.SelfInkOverflow(); rect = text_fragment.SelfInkOverflow();
rect.Move(border_rect.offset); rect.Move(border_rect.offset);
} }
if (!hit_test.location.Intersects(rect))
return false;
if (FragmentVisibleToHitTestRequest(text_fragment, Node* node = text_fragment.NodeForHitTest();
result.GetHitTestRequest()) && if (!hit_test.result->InnerNode() && node) {
hit_test_location.Intersects(rect)) { PhysicalOffset point = hit_test.location.Point() - physical_offset +
Node* node = text_fragment.NodeForHitTest(); text_paint_fragment->InlineOffsetToContainerBox();
if (!result.InnerNode() && node) { hit_test.result->SetNodeAndPosition(node, point);
PhysicalOffset point = hit_test_location.Point() - physical_offset +
text_paint_fragment->InlineOffsetToContainerBox();
result.SetNodeAndPosition(node, point);
}
if (result.AddNodeToListBasedTestResult(node, hit_test_location, rect) ==
kStopHitTesting) {
return true;
}
} }
return false; return hit_test.result->AddNodeToListBasedTestResult(node, hit_test.location,
rect) == kStopHitTesting;
} }
bool NGBoxFragmentPainter::HitTestTextItem( bool NGBoxFragmentPainter::HitTestTextItem(const HitTestContext& hit_test,
HitTestResult& result, const NGFragmentItem& text_item) {
const NGFragmentItem& text_item,
const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset,
HitTestAction action) {
DCHECK(text_item.IsText()); DCHECK(text_item.IsText());
if (action != kHitTestForeground) if (hit_test.action != kHitTestForeground)
return false;
if (!IsVisibleToHitTest(text_item, hit_test.result->GetHitTestRequest()))
return false; return false;
PhysicalRect border_rect(physical_offset, text_item.Size());
// TODO(layout-dev): Clip to line-top/bottom. // TODO(layout-dev): Clip to line-top/bottom.
const PhysicalOffset offset =
hit_test.inline_root_offset + text_item.Offset();
PhysicalRect border_rect(offset, text_item.Size());
PhysicalRect rect(PixelSnappedIntRect(border_rect)); PhysicalRect rect(PixelSnappedIntRect(border_rect));
if (UNLIKELY(result.GetHitTestRequest().GetType() & if (UNLIKELY(hit_test.result->GetHitTestRequest().GetType() &
HitTestRequest::kHitTestVisualOverflow)) { HitTestRequest::kHitTestVisualOverflow)) {
rect = text_item.SelfInkOverflow(); rect = text_item.SelfInkOverflow();
rect.Move(border_rect.offset); rect.Move(border_rect.offset);
} }
if (!hit_test.location.Intersects(rect))
return false;
if (IsVisibleToHitTest(text_item, result.GetHitTestRequest()) && Node* node = text_item.NodeForHitTest();
hit_test_location.Intersects(rect)) { if (!hit_test.result->InnerNode() && node) {
Node* node = text_item.NodeForHitTest(); PhysicalOffset point =
if (!result.InnerNode() && node) { hit_test.location.Point() - hit_test.inline_root_offset;
PhysicalOffset point = hit_test.result->SetNodeAndPosition(node, point);
hit_test_location.Point() - physical_offset + text_item.Offset();
result.SetNodeAndPosition(node, point);
}
if (result.AddNodeToListBasedTestResult(node, hit_test_location, rect) ==
kStopHitTesting) {
return true;
}
} }
return false; return hit_test.result->AddNodeToListBasedTestResult(node, hit_test.location,
rect) == kStopHitTesting;
} }
// Replicates logic in legacy InlineFlowBox::NodeAtPoint(). // Replicates logic in legacy InlineFlowBox::NodeAtPoint().
bool NGBoxFragmentPainter::HitTestLineBoxFragment( bool NGBoxFragmentPainter::HitTestLineBoxFragment(
HitTestResult& result, const HitTestContext& hit_test,
const NGPhysicalLineBoxFragment& fragment, const NGPhysicalLineBoxFragment& fragment,
const NGInlineBackwardCursor& cursor, const NGInlineBackwardCursor& cursor,
const HitTestLocation& hit_test_location, const PhysicalOffset& physical_offset) {
const PhysicalOffset& physical_offset, if (HitTestChildren(hit_test, cursor.CursorForDescendants(), physical_offset))
HitTestAction action) {
if (HitTestChildren(result, cursor.CursorForDescendants(), hit_test_location,
physical_offset, action))
return true; return true;
if (action != kHitTestForeground) if (hit_test.action != kHitTestForeground)
return false; return false;
if (!VisibleToHitTestRequest(result.GetHitTestRequest())) if (!VisibleToHitTestRequest(hit_test.result->GetHitTestRequest()))
return false; return false;
const PhysicalOffset overflow_location = const PhysicalOffset overflow_location =
cursor.CurrentSelfInkOverflow().offset + physical_offset; cursor.CurrentSelfInkOverflow().offset + physical_offset;
if (HitTestClippedOutByBorder(hit_test_location, overflow_location)) if (HitTestClippedOutByBorder(hit_test.location, overflow_location))
return false; return false;
const PhysicalRect bounds_rect(physical_offset, fragment.Size()); const PhysicalRect bounds_rect(physical_offset, fragment.Size());
const ComputedStyle& containing_box_style = box_fragment_.Style(); const ComputedStyle& containing_box_style = box_fragment_.Style();
if (containing_box_style.HasBorderRadius() && if (containing_box_style.HasBorderRadius() &&
!hit_test_location.Intersects(containing_box_style.GetRoundedBorderFor( !hit_test.location.Intersects(
bounds_rect.ToLayoutRect()))) { containing_box_style.GetRoundedBorderFor(bounds_rect.ToLayoutRect())))
return false; return false;
}
// Now hit test ourselves. // Now hit test ourselves.
if (!hit_test_location.Intersects(bounds_rect)) if (!hit_test.location.Intersects(bounds_rect))
return false; return false;
// Floats will be hit-tested in |kHitTestFloat| phase, but // Floats will be hit-tested in |kHitTestFloat| phase, but
...@@ -1643,36 +1635,35 @@ bool NGBoxFragmentPainter::HitTestLineBoxFragment( ...@@ -1643,36 +1635,35 @@ bool NGBoxFragmentPainter::HitTestLineBoxFragment(
// restructuring. Changing the caller logic isn't easy because currently // restructuring. Changing the caller logic isn't easy because currently
// floats are in the bounds of line boxes only in NG. // floats are in the bounds of line boxes only in NG.
if (fragment.HasFloatingDescendantsForPaint()) { if (fragment.HasFloatingDescendantsForPaint()) {
DCHECK_NE(action, kHitTestFloat); DCHECK_NE(hit_test.action, kHitTestFloat);
if (HitTestChildren(result, cursor.CursorForDescendants(), HitTestContext hit_test_float = hit_test;
hit_test_location, physical_offset, kHitTestFloat)) { hit_test_float.action = kHitTestFloat;
if (HitTestChildren(hit_test_float, cursor.CursorForDescendants(),
physical_offset))
return false; return false;
}
} }
Node* node = fragment.NodeForHitTest(); Node* node = fragment.NodeForHitTest();
if (!result.InnerNode() && node) { if (!hit_test.result->InnerNode() && node) {
const PhysicalOffset point = const PhysicalOffset point =
hit_test_location.Point() - physical_offset + cursor.CurrentOffset(); hit_test.location.Point() - physical_offset + cursor.CurrentOffset();
result.SetNodeAndPosition(node, point); hit_test.result->SetNodeAndPosition(node, point);
} }
return result.AddNodeToListBasedTestResult(node, hit_test_location, return hit_test.result->AddNodeToListBasedTestResult(
bounds_rect) == kStopHitTesting; node, hit_test.location, bounds_rect) == kStopHitTesting;
} }
bool NGBoxFragmentPainter::HitTestChildBoxFragment( bool NGBoxFragmentPainter::HitTestChildBoxFragment(
HitTestResult& result, const HitTestContext& hit_test,
const NGPhysicalBoxFragment& fragment, const NGPhysicalBoxFragment& fragment,
const NGInlineBackwardCursor& cursor, const NGInlineBackwardCursor& cursor,
const HitTestLocation& hit_test_location, const PhysicalOffset& physical_offset) {
const PhysicalOffset& physical_offset,
HitTestAction action) {
// Note: Floats should only be hit tested in the |kHitTestFloat| phase, so we // Note: Floats should only be hit tested in the |kHitTestFloat| phase, so we
// shouldn't enter a float when |action| doesn't match. However, as floats may // shouldn't enter a float when |action| doesn't match. However, as floats may
// scatter around in the entire inline formatting context, we should always // scatter around in the entire inline formatting context, we should always
// enter non-floating inline child boxes to search for floats in the // enter non-floating inline child boxes to search for floats in the
// |kHitTestFloat| phase, unless the child box forms another context. // |kHitTestFloat| phase, unless the child box forms another context.
if (fragment.IsFloating() && action != kHitTestFloat) if (fragment.IsFloating() && hit_test.action != kHitTestFloat)
return false; return false;
if (!FragmentRequiresLegacyFallback(fragment)) { if (!FragmentRequiresLegacyFallback(fragment)) {
...@@ -1681,18 +1672,32 @@ bool NGBoxFragmentPainter::HitTestChildBoxFragment( ...@@ -1681,18 +1672,32 @@ bool NGBoxFragmentPainter::HitTestChildBoxFragment(
DCHECK(!fragment.IsAtomicInline()); DCHECK(!fragment.IsAtomicInline());
DCHECK(!fragment.IsFloating()); DCHECK(!fragment.IsFloating());
if (const NGPaintFragment* paint_fragment = cursor.CurrentPaintFragment()) { if (const NGPaintFragment* paint_fragment = cursor.CurrentPaintFragment()) {
if (fragment.IsInlineBox()) {
return NGBoxFragmentPainter(*paint_fragment)
.NodeAtPoint(hit_test, physical_offset);
}
// When traversing into a different inline formatting context,
// |inline_root_offset| needs to be updated.
return NGBoxFragmentPainter(*paint_fragment) return NGBoxFragmentPainter(*paint_fragment)
.NodeAtPoint(result, hit_test_location, physical_offset, action); .NodeAtPoint(*hit_test.result, hit_test.location, physical_offset,
hit_test.action);
} }
const NGFragmentItem* item = cursor.CurrentItem(); const NGFragmentItem* item = cursor.CurrentItem();
DCHECK(item); DCHECK(item);
DCHECK_EQ(item->BoxFragment(), &fragment); DCHECK_EQ(item->BoxFragment(), &fragment);
NGInlineCursor descendants = cursor.CursorForDescendants(); NGInlineCursor descendants = cursor.CursorForDescendants();
if (fragment.IsInlineBox()) {
return NGBoxFragmentPainter(*item, fragment, &descendants)
.NodeAtPoint(hit_test, physical_offset);
}
// When traversing into a different inline formatting context,
// |inline_root_offset| needs to be updated.
return NGBoxFragmentPainter(*item, fragment, &descendants) return NGBoxFragmentPainter(*item, fragment, &descendants)
.NodeAtPoint(result, hit_test_location, physical_offset, action); .NodeAtPoint(*hit_test.result, hit_test.location, physical_offset,
hit_test.action);
} }
if (fragment.IsInline() && action != kHitTestForeground) if (fragment.IsInline() && hit_test.action != kHitTestForeground)
return false; return false;
LayoutBox* const layout_box = ToLayoutBox(fragment.GetMutableLayoutObject()); LayoutBox* const layout_box = ToLayoutBox(fragment.GetMutableLayoutObject());
...@@ -1701,62 +1706,49 @@ bool NGBoxFragmentPainter::HitTestChildBoxFragment( ...@@ -1701,62 +1706,49 @@ bool NGBoxFragmentPainter::HitTestChildBoxFragment(
// Hit test all phases of inline blocks, inline tables, replaced elements and // Hit test all phases of inline blocks, inline tables, replaced elements and
// non-positioned floats as if they created their own stacking contexts. // non-positioned floats as if they created their own stacking contexts.
if (fragment.IsAtomicInline() || fragment.IsFloating()) { if (fragment.IsAtomicInline() || fragment.IsFloating()) {
return layout_box->HitTestAllPhases(result, hit_test_location, return layout_box->HitTestAllPhases(*hit_test.result, hit_test.location,
physical_offset); physical_offset);
} }
return layout_box->NodeAtPoint(result, hit_test_location, physical_offset, return layout_box->NodeAtPoint(*hit_test.result, hit_test.location,
action); physical_offset, hit_test.action);
} }
bool NGBoxFragmentPainter::HitTestChildren( bool NGBoxFragmentPainter::HitTestChildren(
HitTestResult& result, const HitTestContext& hit_test,
const HitTestLocation& hit_test_location, const PhysicalOffset& accumulated_offset) {
const PhysicalOffset& accumulated_offset,
HitTestAction action) {
if (paint_fragment_) { if (paint_fragment_) {
NGInlineCursor cursor(*paint_fragment_); NGInlineCursor cursor(*paint_fragment_);
return HitTestChildren(result, cursor, hit_test_location, return HitTestChildren(hit_test, cursor, accumulated_offset);
accumulated_offset, action);
} }
if (UNLIKELY(descendants_)) { if (UNLIKELY(descendants_)) {
if (!*descendants_) if (*descendants_)
return false; return HitTestChildren(hit_test, *descendants_, accumulated_offset);
return HitTestChildren(result, *descendants_, hit_test_location, return false;
accumulated_offset, action);
} }
if (items_) { if (items_) {
NGInlineCursor cursor(*items_); NGInlineCursor cursor(*items_);
return HitTestChildren(result, cursor, hit_test_location, return HitTestChildren(hit_test, cursor, accumulated_offset);
accumulated_offset, action);
} }
NOTREACHED(); NOTREACHED();
return false; return false;
} }
bool NGBoxFragmentPainter::HitTestChildren( bool NGBoxFragmentPainter::HitTestChildren(
HitTestResult& result, const HitTestContext& hit_test,
const NGInlineCursor& children, const NGInlineCursor& children,
const HitTestLocation& hit_test_location, const PhysicalOffset& accumulated_offset) {
const PhysicalOffset& accumulated_offset, if (children.IsPaintFragmentCursor())
HitTestAction action) { return HitTestPaintFragmentChildren(hit_test, children, accumulated_offset);
if (children.IsPaintFragmentCursor()) { if (children.IsItemCursor())
return HitTestPaintFragmentChildren(result, children, hit_test_location, return HitTestItemsChildren(hit_test, children);
accumulated_offset, action);
}
if (children.IsItemCursor()) {
return HitTestItemsChildren(result, children, hit_test_location,
accumulated_offset, action);
}
// Hits nothing if there were no children. // Hits nothing if there were no children.
return false; return false;
} }
bool NGBoxFragmentPainter::HitTestPaintFragmentChildren( bool NGBoxFragmentPainter::HitTestPaintFragmentChildren(
HitTestResult& result, const HitTestContext& hit_test,
const NGInlineCursor& children, const NGInlineCursor& children,
const HitTestLocation& hit_test_location, const PhysicalOffset& accumulated_offset) {
const PhysicalOffset& accumulated_offset,
HitTestAction action) {
DCHECK(children.IsPaintFragmentCursor()); DCHECK(children.IsPaintFragmentCursor());
for (NGInlineBackwardCursor cursor(children); cursor;) { for (NGInlineBackwardCursor cursor(children); cursor;) {
const NGPaintFragment* child_paint_fragment = cursor.CurrentPaintFragment(); const NGPaintFragment* child_paint_fragment = cursor.CurrentPaintFragment();
...@@ -1771,30 +1763,29 @@ bool NGBoxFragmentPainter::HitTestPaintFragmentChildren( ...@@ -1771,30 +1763,29 @@ bool NGBoxFragmentPainter::HitTestPaintFragmentChildren(
const PhysicalOffset child_offset = const PhysicalOffset child_offset =
child_paint_fragment->Offset() + accumulated_offset; child_paint_fragment->Offset() + accumulated_offset;
if (child_fragment.Type() == NGPhysicalFragment::kFragmentBox) { if (child_fragment.Type() == NGPhysicalFragment::kFragmentBox) {
if (HitTestChildBoxFragment( if (HitTestChildBoxFragment(hit_test,
result, To<NGPhysicalBoxFragment>(child_fragment), cursor, To<NGPhysicalBoxFragment>(child_fragment),
hit_test_location, child_offset, action)) cursor, child_offset))
return true; return true;
} else if (child_fragment.Type() == NGPhysicalFragment::kFragmentLineBox) { } else if (child_fragment.Type() == NGPhysicalFragment::kFragmentLineBox) {
if (HitTestLineBoxFragment( if (HitTestLineBoxFragment(hit_test,
result, To<NGPhysicalLineBoxFragment>(child_fragment), cursor, To<NGPhysicalLineBoxFragment>(child_fragment),
hit_test_location, child_offset, action)) cursor, child_offset))
return true; return true;
} else if (child_fragment.Type() == NGPhysicalFragment::kFragmentText) { } else if (child_fragment.Type() == NGPhysicalFragment::kFragmentText) {
if (HitTestTextFragment(result, cursor, hit_test_location, child_offset, if (HitTestTextFragment(hit_test, cursor, child_offset))
action))
return true; return true;
} }
cursor.MoveToPreviousSibling(); cursor.MoveToPreviousSibling();
if (child_fragment.IsInline() && action == kHitTestForeground) { if (child_fragment.IsInline() && hit_test.action == kHitTestForeground) {
// Hit test culled inline boxes between |fragment| and its parent // Hit test culled inline boxes between |fragment| and its parent
// fragment. // fragment.
const NGPaintFragment* previous_sibling = const NGPaintFragment* previous_sibling =
cursor ? cursor.CurrentPaintFragment() : nullptr; cursor ? cursor.CurrentPaintFragment() : nullptr;
if (HitTestCulledInlineAncestors(result, *child_paint_fragment, if (HitTestCulledInlineAncestors(*hit_test.result, *child_paint_fragment,
previous_sibling, hit_test_location, previous_sibling, hit_test.location,
child_offset)) child_offset))
return true; return true;
} }
...@@ -1804,11 +1795,8 @@ bool NGBoxFragmentPainter::HitTestPaintFragmentChildren( ...@@ -1804,11 +1795,8 @@ bool NGBoxFragmentPainter::HitTestPaintFragmentChildren(
} }
bool NGBoxFragmentPainter::HitTestItemsChildren( bool NGBoxFragmentPainter::HitTestItemsChildren(
HitTestResult& result, const HitTestContext& hit_test,
const NGInlineCursor& children, const NGInlineCursor& children) {
const HitTestLocation& hit_test_location,
const PhysicalOffset& accumulated_offset,
HitTestAction action) {
DCHECK(children.IsItemCursor()); DCHECK(children.IsItemCursor());
for (NGInlineBackwardCursor cursor(children); cursor;) { for (NGInlineBackwardCursor cursor(children); cursor;) {
const NGFragmentItem* item = cursor.CurrentItem(); const NGFragmentItem* item = cursor.CurrentItem();
...@@ -1818,21 +1806,23 @@ bool NGBoxFragmentPainter::HitTestItemsChildren( ...@@ -1818,21 +1806,23 @@ bool NGBoxFragmentPainter::HitTestItemsChildren(
continue; continue;
} }
const PhysicalOffset child_offset = item->Offset() + accumulated_offset;
if (item->IsText()) { if (item->IsText()) {
if (HitTestTextItem(result, *item, hit_test_location, child_offset, if (HitTestTextItem(hit_test, *item))
action))
return true; return true;
} else if (item->Type() == NGFragmentItem::kLine) { } else if (item->Type() == NGFragmentItem::kLine) {
const NGPhysicalLineBoxFragment* child_fragment = item->LineBoxFragment(); const NGPhysicalLineBoxFragment* child_fragment = item->LineBoxFragment();
DCHECK(child_fragment); DCHECK(child_fragment);
if (HitTestLineBoxFragment(result, *child_fragment, cursor, const PhysicalOffset child_offset =
hit_test_location, child_offset, action)) hit_test.inline_root_offset + item->Offset();
if (HitTestLineBoxFragment(hit_test, *child_fragment, cursor,
child_offset))
return true; return true;
} else if (item->Type() == NGFragmentItem::kBox) { } else if (item->Type() == NGFragmentItem::kBox) {
if (const NGPhysicalBoxFragment* child_fragment = item->BoxFragment()) { if (const NGPhysicalBoxFragment* child_fragment = item->BoxFragment()) {
if (HitTestChildBoxFragment(result, *child_fragment, cursor, const PhysicalOffset child_offset =
hit_test_location, child_offset, action)) hit_test.inline_root_offset + item->Offset();
if (HitTestChildBoxFragment(hit_test, *child_fragment, cursor,
child_offset))
return true; return true;
} }
} else { } else {
......
...@@ -159,64 +159,73 @@ class NGBoxFragmentPainter : public BoxPainterBase { ...@@ -159,64 +159,73 @@ class NGBoxFragmentPainter : public BoxPainterBase {
bool IsInSelfHitTestingPhase(HitTestAction) const; bool IsInSelfHitTestingPhase(HitTestAction) const;
bool VisibleToHitTestRequest(const HitTestRequest&) const; bool VisibleToHitTestRequest(const HitTestRequest&) const;
// This struct has common data needed while traversing trees for the hit
// testing.
struct HitTestContext {
STACK_ALLOCATED();
public:
HitTestContext(HitTestAction action,
const HitTestLocation& location,
const PhysicalOffset& inline_root_offset,
HitTestResult* result)
: action(action),
location(location),
inline_root_offset(inline_root_offset),
result(result) {}
HitTestAction action;
const HitTestLocation& location;
// When traversing within an inline formatting context, this member
// represents the offset of the root of the inline formatting context.
PhysicalOffset inline_root_offset;
// The result is set to this member, but its address does not change during
// the traversal.
HitTestResult* result;
};
// Hit tests the children of a container fragment, which is either // Hit tests the children of a container fragment, which is either
// |box_fragment_|, or one of its child line box fragments. // |box_fragment_|, or one of its child line box fragments.
// @param physical_offset Physical offset of the container fragment's content // @param physical_offset Physical offset of the container fragment's content
// 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 NodeAtPoint(const HitTestContext& hit_test,
const HitTestLocation& hit_test_location, const PhysicalOffset& physical_offset);
const PhysicalOffset& physical_offset, bool HitTestChildren(const HitTestContext& hit_test,
HitTestAction); const PhysicalOffset& physical_offset);
bool HitTestChildren(HitTestResult&, bool HitTestChildren(const HitTestContext& hit_test,
const NGInlineCursor& children, const NGInlineCursor& children,
const HitTestLocation& hit_test_location, const PhysicalOffset& physical_offset);
const PhysicalOffset& physical_offset, bool HitTestPaintFragmentChildren(const HitTestContext& hit_test,
HitTestAction);
bool HitTestPaintFragmentChildren(HitTestResult&,
const NGInlineCursor& children, const NGInlineCursor& children,
const HitTestLocation& hit_test_location, const PhysicalOffset& physical_offset);
const PhysicalOffset& physical_offset, bool HitTestItemsChildren(const HitTestContext& hit_test,
HitTestAction); const NGInlineCursor& children);
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(const HitTestContext& hit_test,
const NGPhysicalBoxFragment& fragment, const NGPhysicalBoxFragment& fragment,
const NGInlineBackwardCursor& cursor, const NGInlineBackwardCursor& cursor,
const HitTestLocation& hit_test_location, const PhysicalOffset& physical_offset);
const PhysicalOffset& physical_offset,
HitTestAction);
// 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(const HitTestContext& hit_test,
const NGInlineBackwardCursor& cursor, const NGInlineBackwardCursor& cursor,
const HitTestLocation& hit_test_location, const PhysicalOffset& physical_offset);
const PhysicalOffset& physical_offset, bool HitTestTextItem(const HitTestContext& hit_test,
HitTestAction); const NGFragmentItem& text_item);
bool HitTestTextItem(HitTestResult& result,
const NGFragmentItem& text_item,
const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset,
HitTestAction action);
// Hit tests the given line box fragment. // Hit tests the given line box fragment.
// @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(const HitTestContext& hit_test,
const NGPhysicalLineBoxFragment& fragment, const NGPhysicalLineBoxFragment& fragment,
const NGInlineBackwardCursor& cursor, const NGInlineBackwardCursor& cursor,
const HitTestLocation& hit_test_location, const PhysicalOffset& physical_offset);
const PhysicalOffset& physical_offset,
HitTestAction);
// Returns whether the hit test location is completely outside the border box, // Returns whether the hit test location is completely outside the border box,
// which possibly has rounded corners. // which possibly has rounded corners.
......
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