Example #1
0
HeapVector<Member<Element>> TreeScope::elementsFromHitTestResult(
    HitTestResult& result) const {
  HeapVector<Member<Element>> elements;

  Node* lastNode = nullptr;
  for (const auto rectBasedNode : result.listBasedTestResult()) {
    Node* node = rectBasedNode.get();
    if (!node || !node->isElementNode() || node->isDocumentNode())
      continue;

    if (node->isPseudoElement() || node->isTextNode())
      node = node->parentOrShadowHostNode();
    node = ancestorInThisScope(node);

    // Prune duplicate entries. A pseduo ::before content above its parent
    // node should only result in a single entry.
    if (node == lastNode)
      continue;

    if (node && node->isElementNode()) {
      elements.append(toElement(node));
      lastNode = node;
    }
  }

  if (rootNode().isDocumentNode()) {
    if (Element* rootElement = toDocument(rootNode()).documentElement()) {
      if (elements.isEmpty() || elements.last() != rootElement)
        elements.append(rootElement);
    }
  }

  return elements;
}
Example #2
0
void findGoodTouchTargets(const IntRect& touchBoxInRootFrame, LocalFrame* mainFrame, Vector<IntRect>& goodTargets, WillBeHeapVector<RawPtrWillBeMember<Node>>& highlightNodes)
{
    goodTargets.clear();

    int touchPointPadding = ceil(std::max(touchBoxInRootFrame.width(), touchBoxInRootFrame.height()) * 0.5);

    IntPoint touchPoint = touchBoxInRootFrame.center();
    IntPoint contentsPoint = mainFrame->view()->rootFrameToContents(touchPoint);

    HitTestResult result = mainFrame->eventHandler().hitTestResultAtPoint(contentsPoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ListBased, LayoutSize(touchPointPadding, touchPointPadding));
    const WillBeHeapListHashSet<RefPtrWillBeMember<Node>>& hitResults = result.listBasedTestResult();

    // Blacklist nodes that are container of disambiguated nodes.
    // It is not uncommon to have a clickable <div> that contains other clickable objects.
    // This heuristic avoids excessive disambiguation in that case.
    WillBeHeapHashSet<RawPtrWillBeMember<Node>> blackList;
    for (const auto& hitResult : hitResults) {
        // Ignore any Nodes that can't be clicked on.
        LayoutObject* layoutObject = hitResult.get()->layoutObject();
        if (!layoutObject || !hitResult.get()->willRespondToMouseClickEvents())
            continue;

        // Blacklist all of the Node's containers.
        for (LayoutBlock* container = layoutObject->containingBlock(); container; container = container->containingBlock()) {
            Node* containerNode = container->node();
            if (!containerNode)
                continue;
            if (!blackList.add(containerNode).isNewEntry)
                break;
        }
    }

    WillBeHeapHashMap<RawPtrWillBeMember<Node>, TouchTargetData> touchTargets;
    float bestScore = 0;
    for (const auto& hitResult : hitResults) {
        for (Node* node = hitResult.get(); node; node = node->parentNode()) {
            if (blackList.contains(node))
                continue;
            if (node->isDocumentNode() || isHTMLHtmlElement(*node) || isHTMLBodyElement(*node))
                break;
            if (node->willRespondToMouseClickEvents()) {
                TouchTargetData& targetData = touchTargets.add(node, TouchTargetData()).storedValue->value;
                targetData.windowBoundingBox = boundingBoxForEventNodes(node);
                targetData.score = scoreTouchTarget(touchPoint, touchPointPadding, targetData.windowBoundingBox);
                bestScore = std::max(bestScore, targetData.score);
                break;
            }
        }
    }

    for (const auto& touchTarget : touchTargets) {
        // Currently the scoring function uses the overlap area with the fat point as the score.
        // We ignore the candidates that has less than 1/2 overlap (we consider not really ambiguous enough) than the best candidate to avoid excessive popups.
        if (touchTarget.value.score < bestScore * 0.5)
            continue;
        goodTargets.append(touchTarget.value.windowBoundingBox);
        highlightNodes.append(touchTarget.key);
    }
}