bool LayoutPart::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) { if (!widget() || !widget()->isFrameView() || !result.hitTestRequest().allowsChildFrameContent()) return nodeAtPointOverWidget(result, locationInContainer, accumulatedOffset, action); // A hit test can never hit an off-screen element; only off-screen iframes are throttled; // therefore, hit tests can skip descending into throttled iframes. if (toFrameView(widget())->shouldThrottleRendering()) return nodeAtPointOverWidget(result, locationInContainer, accumulatedOffset, action); ASSERT(document().lifecycle().state() >= DocumentLifecycle::CompositingClean); if (action == HitTestForeground) { FrameView* childFrameView = toFrameView(widget()); LayoutView* childRoot = childFrameView->layoutView(); if (visibleToHitTestRequest(result.hitTestRequest()) && childRoot) { LayoutPoint adjustedLocation = accumulatedOffset + location(); LayoutPoint contentOffset = LayoutPoint(borderLeft() + paddingLeft(), borderTop() + paddingTop()) - LayoutSize(childFrameView->scrollOffset()); HitTestLocation newHitTestLocation(locationInContainer, -adjustedLocation - contentOffset); HitTestRequest newHitTestRequest(result.hitTestRequest().type() | HitTestRequest::ChildFrameHitTest); HitTestResult childFrameResult(newHitTestRequest, newHitTestLocation); // The frame's layout and style must be up-to-date if we reach here. bool isInsideChildFrame = childRoot->hitTestNoLifecycleUpdate(childFrameResult); if (result.hitTestRequest().listBased()) { result.append(childFrameResult); } else if (isInsideChildFrame) { // Force the result not to be cacheable because the parent // frame should not cache this result; as it won't be notified of // changes in the child. childFrameResult.setCacheable(false); result = childFrameResult; } // Don't trust |isInsideChildFrame|. For rect-based hit-test, returns // true only when the hit test rect is totally within the iframe, // i.e. nodeAtPointOverWidget() also returns true. // Use a temporary HitTestResult because we don't want to collect the // iframe element itself if the hit-test rect is totally within the iframe. if (isInsideChildFrame) { if (!locationInContainer.isRectBasedTest()) return true; HitTestResult pointOverWidgetResult = result; bool pointOverWidget = nodeAtPointOverWidget(pointOverWidgetResult, locationInContainer, accumulatedOffset, action); if (pointOverWidget) return true; result = pointOverWidgetResult; return false; } } } return nodeAtPointOverWidget(result, locationInContainer, accumulatedOffset, action); }