void findGoodTouchTargets(const IntRect& touchBox, LocalFrame* mainFrame, Vector<IntRect>& goodTargets, WillBeHeapVector<RawPtrWillBeMember<Node> >& highlightNodes)
{
    goodTargets.clear();

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

    IntPoint touchPoint = touchBox.center();
    IntPoint contentsPoint = mainFrame->view()->windowToContents(touchPoint);

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

    // 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 (WillBeHeapListHashSet<RefPtrWillBeMember<Node> >::const_iterator it = hitResults.begin(); it != hitResults.end(); ++it) {
        // Ignore any Nodes that can't be clicked on.
        RenderObject* renderer = it->get()->renderer();
        if (!renderer || !it->get()->willRespondToMouseClickEvents())
            continue;

        // Blacklist all of the Node's containers.
        for (RenderBlock* container = renderer->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 (WillBeHeapListHashSet<RefPtrWillBeMember<Node> >::const_iterator it = hitResults.begin(); it != hitResults.end(); ++it) {
        for (Node* node = it->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 (WillBeHeapHashMap<RawPtrWillBeMember<Node>, TouchTargetData>::iterator it = touchTargets.begin(); it != touchTargets.end(); ++it) {
        // 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 (it->value.score < bestScore * 0.5)
            continue;
        goodTargets.append(it->value.windowBoundingBox);
        highlightNodes.append(it->key);
    }
}
Example #2
0
void HitTestResult::append(const HitTestResult& other)
{
    ASSERT(isRectBasedTest() && other.isRectBasedTest());

    if (!m_innerNode && other.innerNode()) {
        m_innerNode = other.innerNode();
        m_innerNonSharedNode = other.innerNonSharedNode();
        m_localPoint = other.localPoint();
        m_innerURLElement = other.URLElement();
        m_scrollbar = other.scrollbar();
        m_isOverWidget = other.isOverWidget();
    }

    const ListHashSet<RefPtr<Node> >& list = other.rectBasedTestResult();
    ListHashSet<RefPtr<Node> >::const_iterator last = list.end();
    for (ListHashSet<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it)
        m_rectBasedTestResult.add(it->get());
}
Example #3
0
HitTestResult::HitTestResult(const HitTestResult& other)
    : m_innerNode(other.innerNode())
    , m_innerNonSharedNode(other.innerNonSharedNode())
    , m_point(other.point())
    , m_localPoint(other.localPoint())
    , m_innerURLElement(other.URLElement())
    , m_scrollbar(other.scrollbar())
    , m_isOverWidget(other.isOverWidget())
{
    // Only copy the padding and ListHashSet in case of rect hit test.
    // Copying the later is rather expensive.
    if ((m_isRectBased = other.isRectBasedTest())) {
        m_topPadding = other.m_topPadding;
        m_rightPadding = other.m_rightPadding;
        m_bottomPadding = other.m_bottomPadding;
        m_leftPadding = other.m_leftPadding;
        m_rectBasedTestResult = other.rectBasedTestResult();
    } else
        m_topPadding = m_rightPadding = m_bottomPadding = m_leftPadding = 0;
}