Ejemplo n.º 1
0
void EventRetargeter::calculateEventPath(Node* targetNode, Event* event, EventPath& eventPath)
{
    bool inDocument = targetNode->inDocument();
    bool isSVGElement = targetNode->isSVGElement();
    bool isMouseOrFocusEvent = event->isMouseEvent() || event->isFocusEvent();
#if ENABLE(TOUCH_EVENTS)
    bool isTouchEvent = event->isTouchEvent();
#endif
    Vector<EventTarget*, 32> targetStack;

    for (Node* node = nodeOrHostIfPseudoElement(targetNode); node; node = node->parentOrShadowHostNode()) {
        if (targetStack.isEmpty())
            targetStack.append(eventTargetRespectingTargetRules(node));
        if (isMouseOrFocusEvent)
            eventPath.append(adoptPtr(new MouseOrFocusEventContext(node, eventTargetRespectingTargetRules(node), targetStack.last())));
#if ENABLE(TOUCH_EVENTS)
        else if (isTouchEvent)
            eventPath.append(adoptPtr(new TouchEventContext(node, eventTargetRespectingTargetRules(node), targetStack.last())));
#endif
        else
            eventPath.append(adoptPtr(new EventContext(node, eventTargetRespectingTargetRules(node), targetStack.last())));
        if (!inDocument)
            return;
        if (!node->isShadowRoot())
            continue;
        if (determineDispatchBehavior(event, toShadowRoot(node), targetStack.last()) == StayInsideShadowDOM)
            return;
        if (!isSVGElement) {
            ASSERT(!targetStack.isEmpty());
            targetStack.removeLast();
        }
    }
}
Ejemplo n.º 2
0
Element* TreeScope::adjustedFocusedElement() const {
  Document& document = rootNode().document();
  Element* element = document.focusedElement();
  if (!element && document.page())
    element = document.page()->focusController().focusedFrameOwnerElement(
        *document.frame());
  if (!element)
    return nullptr;

  if (rootNode().isInV1ShadowTree()) {
    if (Element* retargeted = retarget(*element)) {
      return (this == &retargeted->treeScope()) ? retargeted : nullptr;
    }
    return nullptr;
  }

  EventPath* eventPath = new EventPath(*element);
  for (size_t i = 0; i < eventPath->size(); ++i) {
    if (eventPath->at(i).node() == rootNode()) {
      // eventPath->at(i).target() is one of the followings:
      // - InsertionPoint
      // - shadow host
      // - Document::focusedElement()
      // So, it's safe to do toElement().
      return toElement(eventPath->at(i).target()->toNode());
    }
  }
  return nullptr;
}
Ejemplo n.º 3
0
void EventRetargeter::calculateEventPath(Node* node, Event* event, EventPath& eventPath)
{
    bool inDocument = node->inDocument();
    bool isSVGElement = node->isSVGElement();
    bool isMouseOrFocusEvent = event->isMouseEvent() || event->isFocusEvent();
#if ENABLE(TOUCH_EVENTS)
    bool isTouchEvent = event->isTouchEvent();
#endif
    Vector<EventTarget*, 32> targetStack;
    for (EventPathWalker walker(node); walker.node(); walker.moveToParent()) {
        Node* node = walker.node();
        if (targetStack.isEmpty())
            targetStack.append(eventTargetRespectingTargetRules(node));
        else if (walker.isVisitingInsertionPointInReprojection())
            targetStack.append(targetStack.last());
        if (isMouseOrFocusEvent)
            eventPath.append(adoptPtr(new MouseOrFocusEventContext(node, eventTargetRespectingTargetRules(node), targetStack.last())));
#if ENABLE(TOUCH_EVENTS)
        else if (isTouchEvent)
            eventPath.append(adoptPtr(new TouchEventContext(node, eventTargetRespectingTargetRules(node), targetStack.last())));
#endif
        else
            eventPath.append(adoptPtr(new EventContext(node, eventTargetRespectingTargetRules(node), targetStack.last())));
        if (!inDocument)
            return;
        if (!node->isShadowRoot())
            continue;
        if (determineDispatchBehavior(event, toShadowRoot(node), targetStack.last()) == StayInsideShadowDOM)
            return;
        if (!isSVGElement) {
            ASSERT(!targetStack.isEmpty());
            targetStack.removeLast();
        }
    }
}
Ejemplo n.º 4
0
static void callDefaultEventHandlersInTheBubblingOrder(Event& event, const EventPath& path)
{
    // Non-bubbling events call only one default event handler, the one for the target.
    path.contextAt(0).node()->defaultEventHandler(&event);
    ASSERT(!event.defaultPrevented());

    if (event.defaultHandled() || !event.bubbles())
        return;

    size_t size = path.size();
    for (size_t i = 1; i < size; ++i) {
        path.contextAt(i).node()->defaultEventHandler(&event);
        ASSERT(!event.defaultPrevented());
        if (event.defaultHandled())
            return;
    }
}
Ejemplo n.º 5
0
PassRefPtr<StaticNodeList> TreeScopeEventContext::ensureEventPath(EventPath& path)
{
    if (m_eventPath)
        return m_eventPath;

    Vector<RefPtr<Node> > nodes;
    nodes.reserveInitialCapacity(path.size());
    for (size_t i = 0; i < path.size(); ++i) {
        TreeScope& treeScope = path[i].treeScopeEventContext().treeScope();
        if (treeScope.rootNode().isShadowRoot())
            nodes.append(path[i].node());
        else if (path[i].treeScopeEventContext().isInclusiveAncestorOf(*this))
            nodes.append(path[i].node());
    }
    m_eventPath = StaticNodeList::adopt(nodes);
    return m_eventPath;
}
Ejemplo n.º 6
0
static void dispatchEventInDOM(Event& event, const EventPath& path, WindowEventContext& windowEventContext)
{
    // Trigger capturing event handlers, starting at the top and working our way down.
    event.setEventPhase(Event::CAPTURING_PHASE);

    // We don't dispatch load events to the window. This quirk was originally
    // added because Mozilla doesn't propagate load events to the window object.
    bool shouldFireEventAtWindow = event.type() != eventNames().loadEvent;
    if (shouldFireEventAtWindow && windowEventContext.handleLocalEvents(event) && event.propagationStopped())
        return;

    for (size_t i = path.size() - 1; i > 0; --i) {
        const EventContext& eventContext = path.contextAt(i);
        if (eventContext.currentTargetSameAsTarget())
            continue;
        eventContext.handleLocalEvents(event);
        if (event.propagationStopped())
            return;
    }

    event.setEventPhase(Event::AT_TARGET);
    path.contextAt(0).handleLocalEvents(event);
    if (event.propagationStopped())
        return;

    // Trigger bubbling event handlers, starting at the bottom and working our way up.
    size_t size = path.size();
    for (size_t i = 1; i < size; ++i) {
        const EventContext& eventContext = path.contextAt(i);
        if (eventContext.currentTargetSameAsTarget())
            event.setEventPhase(Event::AT_TARGET);
        else if (event.bubbles() && !event.cancelBubble())
            event.setEventPhase(Event::BUBBLING_PHASE);
        else
            continue;
        eventContext.handleLocalEvents(event);
        if (event.propagationStopped())
            return;
    }
    if (event.bubbles() && !event.cancelBubble()) {
        event.setEventPhase(Event::BUBBLING_PHASE);
        if (shouldFireEventAtWindow)
            windowEventContext.handleLocalEvents(event);
    }
}
Ejemplo n.º 7
0
void EventRetargeter::calculateAdjustedNodes(const Node* node, const Node* relatedNode, EventWithRelatedTargetDispatchBehavior eventWithRelatedTargetDispatchBehavior, EventPath& eventPath, AdjustedNodes& adjustedNodes)
{
    RelatedNodeMap relatedNodeMap;
    buildRelatedNodeMap(relatedNode, relatedNodeMap);

    // Synthetic mouse events can have a relatedTarget which is identical to the target.
    bool targetIsIdenticalToToRelatedTarget = (node == relatedNode);

    TreeScope* lastTreeScope = 0;
    Node* adjustedNode = 0;
    for (EventPath::const_iterator iter = eventPath.begin(); iter < eventPath.end(); ++iter) {
        TreeScope* scope = (*iter)->node()->treeScope();
        if (scope == lastTreeScope) {
            // Re-use the previous adjustedRelatedTarget if treeScope does not change. Just for the performance optimization.
            adjustedNodes.append(adjustedNode);
        } else {
            adjustedNode = findRelatedNode(scope, relatedNodeMap);
            adjustedNodes.append(adjustedNode);
        }
        lastTreeScope = scope;
        if (eventWithRelatedTargetDispatchBehavior == DoesNotStopAtBoundary)
            continue;
        if (targetIsIdenticalToToRelatedTarget) {
            if (node->treeScope()->rootNode() == (*iter)->node()) {
                eventPath.shrink(iter + 1 - eventPath.begin());
                break;
            }
        } else if ((*iter)->target() == adjustedNode) {
            // Event dispatching should be stopped here.
            eventPath.shrink(iter - eventPath.begin());
            adjustedNodes.shrink(adjustedNodes.size() - 1);
            break;
        }
    }
}
Ejemplo n.º 8
0
void EventRetargeter::adjustTouchList(const Node* node, const TouchList* touchList, const EventPath& eventPath, EventPathTouchLists& eventPathTouchLists)
{
    if (!touchList)
        return;
    size_t eventPathSize = eventPath.size();
    ASSERT(eventPathTouchLists.size() == eventPathSize);
    for (size_t i = 0; i < touchList->length(); ++i) {
        const Touch& touch = *touchList->item(i);
        AdjustedNodes adjustedNodes;
        calculateAdjustedNodes(node, touch.target()->toNode(), DoesNotStopAtBoundary, const_cast<EventPath&>(eventPath), adjustedNodes);
        ASSERT(adjustedNodes.size() == eventPathSize);
        for (size_t j = 0; j < eventPathSize; ++j)
            eventPathTouchLists[j]->append(touch.cloneWithNewTarget(adjustedNodes[j].get()));
    }
}
Ejemplo n.º 9
0
static bool eventHasListeners(const AtomicString& eventType, DOMWindow* window, Node* node, const EventPath& eventPath)
{
    if (window && window->hasEventListeners(eventType))
        return true;

    if (node->hasEventListeners(eventType))
        return true;

    for (size_t i = 0; i < eventPath.size(); i++) {
        if (eventPath[i]->node()->hasEventListeners(eventType))
            return true;
    }

    return false;
}
Ejemplo n.º 10
0
void EventRetargeter::adjustForRelatedTarget(const Node* node, EventTarget* relatedTarget, EventPath& eventPath)
{
    if (!node)
        return;
    if (!relatedTarget)
        return;
    Node* relatedNode = relatedTarget->toNode();
    if (!relatedNode)
        return;
    AdjustedNodes adjustedNodes;
    calculateAdjustedNodes(node, relatedNode, StopAtBoundaryIfNeeded, eventPath, adjustedNodes);
    ASSERT(adjustedNodes.size() <= eventPath.size());
    for (size_t i = 0; i < adjustedNodes.size(); ++i) {
        ASSERT(eventPath[i]->isMouseOrFocusEventContext());
        MouseOrFocusEventContext* mouseOrFocusEventContext = static_cast<MouseOrFocusEventContext*>(eventPath[i].get());
        mouseOrFocusEventContext->setRelatedTarget(adjustedNodes[i]);
    }
}
Ejemplo n.º 11
0
void EventRetargeter::adjustForTouchEvent(Node* node, const TouchEvent& touchEvent, EventPath& eventPath)
{
    size_t eventPathSize = eventPath.size();

    EventPathTouchLists eventPathTouches(eventPathSize);
    EventPathTouchLists eventPathTargetTouches(eventPathSize);
    EventPathTouchLists eventPathChangedTouches(eventPathSize);

    for (size_t i = 0; i < eventPathSize; ++i) {
        ASSERT(eventPath[i]->isTouchEventContext());
        TouchEventContext* touchEventContext = toTouchEventContext(eventPath[i].get());
        eventPathTouches[i] = touchEventContext->touches();
        eventPathTargetTouches[i] = touchEventContext->targetTouches();
        eventPathChangedTouches[i] = touchEventContext->changedTouches();
    }

    adjustTouchList(node, touchEvent.touches(), eventPath, eventPathTouches);
    adjustTouchList(node, touchEvent.targetTouches(), eventPath, eventPathTargetTouches);
    adjustTouchList(node, touchEvent.changedTouches(), eventPath, eventPathChangedTouches);
}