bool hitTestFlow(const RenderBlockFlow& flow, const Layout& layout, const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { if (hitTestAction != HitTestForeground) return false; if (!layout.runCount()) return false; RenderStyle& style = flow.style(); if (style.visibility() != VISIBLE || style.pointerEvents() == PE_NONE) return false; RenderObject& renderer = *flow.firstChild(); LayoutRect rangeRect = locationInContainer.boundingBox(); rangeRect.moveBy(-accumulatedOffset); auto resolver = lineResolver(flow, layout); for (FloatRect lineRect : resolver.rangeForRect(rangeRect)) { lineRect.moveBy(accumulatedOffset); if (!locationInContainer.intersects(lineRect)) continue; renderer.updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); if (!result.addNodeToRectBasedTestResult(renderer.node(), request, locationInContainer, lineRect)) return true; } return false; }
bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestRequest& request, const HitTestLocation& locationInContainer, const FloatRect& rect) { // If it is not a rect-based hit test, this method has to be no-op. // Return false, so the hit test stops. if (!isRectBasedTest()) return false; // If node is null, return true so the hit test can continue. if (!node) return true; if (!request.allowsShadowContent()) node = node->shadowAncestorNode(); mutableRectBasedTestResult().add(node); bool regionFilled = rect.contains(locationInContainer.boundingBox()); // FIXME: This code (incorrectly) attempts to correct for culled inline nodes. See https://bugs.webkit.org/show_bug.cgi?id=85849. if (node->renderer()->isInline() && !regionFilled) { for (RenderObject* curr = node->renderer()->parent(); curr; curr = curr->parent()) { if (!curr->isRenderInline()) break; // We need to make sure the nodes for culled inlines get included. RenderInline* currInline = toRenderInline(curr); if (currInline->alwaysCreateLineBoxes()) break; if (currInline->visibleToHitTesting() && currInline->node()) mutableRectBasedTestResult().add(currInline->node()->shadowAncestorNode()); } } return !regionFilled; }
bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestRequest& request, const HitTestLocation& locationInContainer, const FloatRect& rect) { // If it is not a rect-based hit test, this method has to be no-op. // Return false, so the hit test stops. if (!isRectBasedTest()) return false; // If node is null, return true so the hit test can continue. if (!node) return true; mutableRectBasedTestResult().add(node); bool regionFilled = rect.contains(locationInContainer.boundingBox()); return !regionFilled; }
ListBasedHitTestBehavior HitTestResult::addNodeToListBasedTestResult(Node* node, const HitTestLocation& location, const Region& region) { // If not a list-based test, stop testing because the hit has been found. if (!hitTestRequest().listBased()) return StopHitTesting; if (!node) return ContinueHitTesting; mutableListBasedTestResult().add(node); if (hitTestRequest().penetratingList()) return ContinueHitTesting; return region.contains(location.boundingBox()) ? StopHitTesting : ContinueHitTesting; }
bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestRequest& request, const HitTestLocation& locationInContainer, const LayoutRect& rect) { // If it is not a rect-based hit test, this method has to be no-op. // Return false, so the hit test stops. if (!isRectBasedTest()) return false; // If node is null, return true so the hit test can continue. if (!node) return true; if (request.disallowsShadowContent()) node = node->document()->ancestorInThisScope(node); mutableRectBasedTestResult().add(node); bool regionFilled = rect.contains(locationInContainer.boundingBox()); return !regionFilled; }