void EventTargetNode::dispatchWindowEvent(const AtomicString& eventType, bool canBubbleArg, bool cancelableArg) { ASSERT(!eventDispatchForbidden()); RefPtr<Document> doc = document(); dispatchWindowEvent(Event::create(eventType, canBubbleArg, cancelableArg)); if (eventType == eventNames().loadEvent) { // For onload events, send a separate load event to the enclosing frame only. // This is a DOM extension and is independent of bubbling/capturing rules of // the DOM. Element* ownerElement = doc->ownerElement(); if (ownerElement) { RefPtr<Event> ownerEvent = Event::create(eventType, false, cancelableArg); ownerEvent->setTarget(ownerElement); ownerElement->dispatchGenericEvent(ownerEvent.release()); } } }
bool EventTargetNode::dispatchMouseEvent(const PlatformMouseEvent& event, const AtomicString& eventType, int detail, Node* relatedTarget) { ASSERT(!eventDispatchForbidden()); IntPoint contentsPos; if (FrameView* view = document()->view()) contentsPos = view->windowToContents(event.pos()); short button = event.button(); ASSERT(event.eventType() == MouseEventMoved || button != NoButton); return dispatchMouseEvent(eventType, button, detail, contentsPos.x(), contentsPos.y(), event.globalX(), event.globalY(), event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), false, relatedTarget); }
void EventTargetNode::dispatchWheelEvent(PlatformWheelEvent& e) { ASSERT(!eventDispatchForbidden()); if (e.deltaX() == 0 && e.deltaY() == 0) return; FrameView* view = document()->view(); if (!view) return; IntPoint pos = view->windowToContents(e.pos()); RefPtr<WheelEvent> we = WheelEvent::create(e.deltaX(), e.deltaY(), document()->defaultView(), e.globalX(), e.globalY(), pos.x(), pos.y(), e.ctrlKey(), e.altKey(), e.shiftKey(), e.metaKey()); ExceptionCode ec = 0; if (!dispatchEvent(we.release(), ec, true)) e.accept(); }
bool SVGElementInstance::dispatchEvent(PassRefPtr<Event> e, ExceptionCode& ec) { RefPtr<Event> evt(e); ASSERT(!eventDispatchForbidden()); if (!evt || evt->type().isEmpty()) { ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR; return false; } // The event has to be dispatched to the shadowTreeElement(), not the correspondingElement()! SVGElement* element = shadowTreeElement(); if (!element) return false; evt->setTarget(this); RefPtr<FrameView> view = element->document()->view(); return element->dispatchGenericEvent(evt.release(), ec); }
bool EventDispatcher::dispatchMouseEvent(Node* node, const PlatformMouseEvent& event, const AtomicString& eventType, int detail, Node* relatedTargetArg) { ASSERT(!eventDispatchForbidden()); ASSERT(event.eventType() == MouseEventMoved || event.button() != NoButton); if (node->disabled()) // Don't even send DOM events for disabled controls.. return true; if (eventType.isEmpty()) return false; // Shouldn't happen. EventDispatcher dispatcher(node); // Attempting to dispatch with a non-EventTarget relatedTarget causes the relatedTarget to be silently ignored. RefPtr<Node> relatedTarget = pullOutOfShadow(relatedTargetArg); RefPtr<MouseEvent> mouseEvent = MouseEvent::create(eventType, node->document()->defaultView(), event, detail, relatedTarget); bool swallowEvent = false; dispatcher.dispatchEvent(mouseEvent); bool defaultHandled = mouseEvent->defaultHandled(); bool defaultPrevented = mouseEvent->defaultPrevented(); if (defaultHandled || defaultPrevented) swallowEvent = true; // Special case: If it's a double click event, we also send the dblclick event. This is not part // of the DOM specs, but is used for compatibility with the ondblclick="" attribute. This is treated // as a separate event in other DOM-compliant browsers like Firefox, and so we do the same. if (eventType == eventNames().clickEvent && detail == 2) { RefPtr<Event> doubleClickEvent = MouseEvent::create(eventNames().dblclickEvent, node->document()->defaultView(), event, detail, relatedTarget); if (defaultHandled) doubleClickEvent->setDefaultHandled(); dispatcher.dispatchEvent(doubleClickEvent); if (doubleClickEvent->defaultHandled() || doubleClickEvent->defaultPrevented()) swallowEvent = true; } return swallowEvent; }
void EventTargetNode::dispatchSimulatedMouseEvent(const AtomicString& eventType, PassRefPtr<Event> underlyingEvent) { ASSERT(!eventDispatchForbidden()); bool ctrlKey = false; bool altKey = false; bool shiftKey = false; bool metaKey = false; if (UIEventWithKeyState* keyStateEvent = findEventWithKeyState(underlyingEvent.get())) { ctrlKey = keyStateEvent->ctrlKey(); altKey = keyStateEvent->altKey(); shiftKey = keyStateEvent->shiftKey(); metaKey = keyStateEvent->metaKey(); } // Like Gecko, we just pass 0 for everything when we make a fake mouse event. // Internet Explorer instead gives the current mouse position and state. dispatchMouseEvent(eventType, 0, 0, 0, 0, 0, 0, ctrlKey, altKey, shiftKey, metaKey, true, 0, underlyingEvent); }
bool EventDispatcher::dispatchEvent(PassRefPtr<Event> event) { event->setTarget(eventTargetRespectingSVGTargetRules(m_node.get())); ASSERT(!eventDispatchForbidden()); ASSERT(event->target()); ASSERT(!event->type().isNull()); // JavaScript code can create an event with an empty name, but not null. RefPtr<EventTarget> originalTarget = event->target(); ensureEventAncestors(event.get()); WindowEventContext windowContext(event.get(), m_node.get(), topEventContext()); InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEvent(m_node->document(), *event, windowContext.window(), m_node.get(), m_ancestors); // Give the target node a chance to do some work before DOM event handlers get a crack. void* data = m_node->preDispatchEventHandler(event.get()); if (m_ancestors.isEmpty() || m_shouldPreventDispatch || event->propagationStopped()) goto doneDispatching; // Trigger capturing event handlers, starting at the top and working our way down. event->setEventPhase(Event::CAPTURING_PHASE); if (windowContext.handleLocalEvents(event.get()) && event->propagationStopped()) goto doneDispatching; for (size_t i = m_ancestors.size() - 1; i > 0; --i) { const EventContext& eventContext = m_ancestors[i]; if (eventContext.currentTargetSameAsTarget()) { if (event->bubbles()) continue; event->setEventPhase(Event::AT_TARGET); } else event->setEventPhase(Event::CAPTURING_PHASE); eventContext.handleLocalEvents(event.get()); if (event->propagationStopped()) goto doneDispatching; } event->setEventPhase(Event::AT_TARGET); event->setTarget(originalTarget.get()); event->setCurrentTarget(eventTargetRespectingSVGTargetRules(m_node.get())); m_ancestors[0].handleLocalEvents(event.get()); if (event->propagationStopped()) goto doneDispatching; if (event->bubbles() && !event->cancelBubble()) { // Trigger bubbling event handlers, starting at the bottom and working our way up. event->setEventPhase(Event::BUBBLING_PHASE); size_t size = m_ancestors.size(); for (size_t i = 1; i < size; ++i) { const EventContext& eventContext = m_ancestors[i]; if (eventContext.currentTargetSameAsTarget()) event->setEventPhase(Event::AT_TARGET); else event->setEventPhase(Event::BUBBLING_PHASE); eventContext.handleLocalEvents(event.get()); if (event->propagationStopped() || event->cancelBubble()) goto doneDispatching; } windowContext.handleLocalEvents(event.get()); } doneDispatching: event->setTarget(originalTarget.get()); event->setCurrentTarget(0); event->setEventPhase(0); // Pass the data from the preDispatchEventHandler to the postDispatchEventHandler. m_node->postDispatchEventHandler(event.get(), data); // Call default event handlers. While the DOM does have a concept of preventing // default handling, the detail of which handlers are called is an internal // implementation detail and not part of the DOM. if (!event->defaultPrevented() && !event->defaultHandled()) { // Non-bubbling events call only one default event handler, the one for the target. m_node->defaultEventHandler(event.get()); ASSERT(!event->defaultPrevented()); if (event->defaultHandled()) goto doneWithDefault; // For bubbling events, call default event handlers on the same targets in the // same order as the bubbling phase. if (event->bubbles()) { size_t size = m_ancestors.size(); for (size_t i = 1; i < size; ++i) { m_ancestors[i].node()->defaultEventHandler(event.get()); ASSERT(!event->defaultPrevented()); if (event->defaultHandled()) goto doneWithDefault; } } } doneWithDefault: // Ensure that after event dispatch, the event's target object is the // outermost shadow DOM boundary. event->setTarget(windowContext.target()); event->setCurrentTarget(0); InspectorInstrumentation::didDispatchEvent(cookie); return !event->defaultPrevented(); }
bool EventTargetNode::dispatchProgressEvent(const AtomicString &eventType, bool lengthComputableArg, unsigned loadedArg, unsigned totalArg) { ASSERT(!eventDispatchForbidden()); ExceptionCode ec = 0; return dispatchEvent(ProgressEvent::create(eventType, lengthComputableArg, loadedArg, totalArg), ec, true); }
bool EventTargetNode::dispatchHTMLEvent(const AtomicString &eventType, bool canBubbleArg, bool cancelableArg) { ASSERT(!eventDispatchForbidden()); ExceptionCode ec = 0; return dispatchEvent(Event::create(eventType, canBubbleArg, cancelableArg), ec, true); }
bool EventTargetNode::dispatchMouseEvent(const AtomicString& eventType, int button, int detail, int pageX, int pageY, int screenX, int screenY, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool isSimulated, Node* relatedTargetArg, PassRefPtr<Event> underlyingEvent) { ASSERT(!eventDispatchForbidden()); if (disabled()) // Don't even send DOM events for disabled controls.. return true; if (eventType.isEmpty()) return false; // Shouldn't happen. // Dispatching the first event can easily result in this node being destroyed. // Since we dispatch up to three events here, we need to make sure we're referenced // so the pointer will be good for the two subsequent ones. RefPtr<Node> protect(this); bool cancelable = eventType != eventNames().mousemoveEvent; ExceptionCode ec = 0; bool swallowEvent = false; // Attempting to dispatch with a non-EventTarget relatedTarget causes the relatedTarget to be silently ignored. RefPtr<EventTargetNode> relatedTarget = (relatedTargetArg && relatedTargetArg->isEventTargetNode()) ? static_cast<EventTargetNode*>(relatedTargetArg) : 0; if (Frame* frame = document()->frame()) { float pageZoom = frame->pageZoomFactor(); if (pageZoom != 1.0f) { // Adjust our pageX and pageY to account for the page zoom. pageX = lroundf(pageX / pageZoom); pageY = lroundf(pageY / pageZoom); } } RefPtr<Event> mouseEvent = MouseEvent::create(eventType, true, cancelable, document()->defaultView(), detail, screenX, screenY, pageX, pageY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget, 0, isSimulated); mouseEvent->setUnderlyingEvent(underlyingEvent.get()); dispatchEvent(mouseEvent, ec); bool defaultHandled = mouseEvent->defaultHandled(); bool defaultPrevented = mouseEvent->defaultPrevented(); if (defaultHandled || defaultPrevented) swallowEvent = true; // Special case: If it's a double click event, we also send the dblclick event. This is not part // of the DOM specs, but is used for compatibility with the ondblclick="" attribute. This is treated // as a separate event in other DOM-compliant browsers like Firefox, and so we do the same. if (eventType == eventNames().clickEvent && detail == 2) { RefPtr<Event> doubleClickEvent = MouseEvent::create(eventNames().dblclickEvent, true, cancelable, document()->defaultView(), detail, screenX, screenY, pageX, pageY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget, 0, isSimulated); doubleClickEvent->setUnderlyingEvent(underlyingEvent.get()); if (defaultHandled) doubleClickEvent->setDefaultHandled(); dispatchEvent(doubleClickEvent, ec); if (doubleClickEvent->defaultHandled() || doubleClickEvent->defaultPrevented()) swallowEvent = true; } return swallowEvent; }
bool EventTargetNode::dispatchGenericEvent(PassRefPtr<Event> prpEvent) { RefPtr<Event> event(prpEvent); ASSERT(!eventDispatchForbidden()); ASSERT(event->target()); ASSERT(!event->type().isNull()); // JavaScript code can create an event with an empty name, but not null. // Make a vector of ancestors to send the event to. // If the node is not in a document just send the event to it. // Be sure to ref all of nodes since event handlers could result in the last reference going away. RefPtr<EventTargetNode> thisNode(this); Vector<RefPtr<ContainerNode> > ancestors; if (inDocument()) { for (ContainerNode* ancestor = eventParentNode(); ancestor; ancestor = ancestor->eventParentNode()) { #if ENABLE(SVG) // Skip <use> shadow tree elements. if (ancestor->isSVGElement() && ancestor->isShadowNode()) continue; #endif ancestors.append(ancestor); } } // Set up a pointer to indicate whether to dispatch window events. // We don't dispatch load events to the window. That quirk was originally // added because Mozilla doesn't propagate load events to the window object. Document* documentForWindowEvents = 0; if (event->type() != eventNames().loadEvent) { EventTargetNode* topLevelContainer = ancestors.isEmpty() ? this : ancestors.last().get(); if (topLevelContainer->isDocumentNode()) documentForWindowEvents = static_cast<Document*>(topLevelContainer); } // Give the target node a chance to do some work before DOM event handlers get a crack. void* data = preDispatchEventHandler(event.get()); if (event->propagationStopped()) goto doneDispatching; // Trigger capturing event handlers, starting at the top and working our way down. event->setEventPhase(Event::CAPTURING_PHASE); if (documentForWindowEvents) { event->setCurrentTarget(documentForWindowEvents); documentForWindowEvents->handleWindowEvent(event.get(), true); if (event->propagationStopped()) goto doneDispatching; } for (size_t i = ancestors.size(); i; --i) { ContainerNode* ancestor = ancestors[i - 1].get(); event->setCurrentTarget(eventTargetRespectingSVGTargetRules(ancestor)); ancestor->handleLocalEvents(event.get(), true); if (event->propagationStopped()) goto doneDispatching; } event->setEventPhase(Event::AT_TARGET); // We do want capturing event listeners to be invoked here, even though // that violates some versions of the DOM specification; Mozilla does it. event->setCurrentTarget(eventTargetRespectingSVGTargetRules(this)); handleLocalEvents(event.get(), true); if (event->propagationStopped()) goto doneDispatching; handleLocalEvents(event.get(), false); if (event->propagationStopped()) goto doneDispatching; if (event->bubbles() && !event->cancelBubble()) { // Trigger bubbling event handlers, starting at the bottom and working our way up. event->setEventPhase(Event::BUBBLING_PHASE); size_t size = ancestors.size(); for (size_t i = 0; i < size; ++i) { ContainerNode* ancestor = ancestors[i].get(); event->setCurrentTarget(eventTargetRespectingSVGTargetRules(ancestor)); ancestor->handleLocalEvents(event.get(), false); if (event->propagationStopped() || event->cancelBubble()) goto doneDispatching; } if (documentForWindowEvents) { event->setCurrentTarget(documentForWindowEvents); documentForWindowEvents->handleWindowEvent(event.get(), false); if (event->propagationStopped() || event->cancelBubble()) goto doneDispatching; } } doneDispatching: event->setCurrentTarget(0); event->setEventPhase(0); // Pass the data from the preDispatchEventHandler to the postDispatchEventHandler. postDispatchEventHandler(event.get(), data); // Call default event handlers. While the DOM does have a concept of preventing // default handling, the detail of which handlers are called is an internal // implementation detail and not part of the DOM. if (!event->defaultPrevented() && !event->defaultHandled()) { // Non-bubbling events call only one default event handler, the one for the target. defaultEventHandler(event.get()); ASSERT(!event->defaultPrevented()); if (event->defaultHandled()) goto doneWithDefault; // For bubbling events, call default event handlers on the same targets in the // same order as the bubbling phase. if (event->bubbles()) { size_t size = ancestors.size(); for (size_t i = 0; i < size; ++i) { ContainerNode* ancestor = ancestors[i].get(); ancestor->defaultEventHandler(event.get()); ASSERT(!event->defaultPrevented()); if (event->defaultHandled()) goto doneWithDefault; } } } doneWithDefault: Document::updateDocumentsRendering(); return !event->defaultPrevented(); }
bool EventTarget::dispatchGenericEvent(EventTargetNode* referenceNode, PassRefPtr<Event> e, ExceptionCode&, bool tempEvent) { RefPtr<Event> evt(e); ASSERT(!eventDispatchForbidden()); ASSERT(evt->target()); ASSERT(!evt->type().isNull()); // JavaScript code could create an event with an empty name // work out what nodes to send event to DeprecatedPtrList<Node> nodeChain; if (referenceNode->inDocument()) { for (Node* n = referenceNode; n; n = n->eventParentNode()) { n->ref(); nodeChain.prepend(n); } } else { // if node is not in the document just send event to itself referenceNode->ref(); nodeChain.prepend(referenceNode); } DeprecatedPtrListIterator<Node> it(nodeChain); // Before we begin dispatching events, give the target node a chance to do some work prior // to the DOM event handlers getting a crack. void* data = preDispatchEventHandler(evt.get()); // trigger any capturing event handlers on our way down evt->setEventPhase(Event::CAPTURING_PHASE); it.toFirst(); // Handle window events for capture phase, except load events, this quirk is needed // because Mozilla used to never propagate load events to the window object if (evt->type() != eventNames().loadEvent && it.current()->isDocumentNode() && !evt->propagationStopped()) static_cast<Document*>(it.current())->handleWindowEvent(evt.get(), true); EventTargetNode* eventTargetNode = 0; for (; it.current() && it.current() != referenceNode && !evt->propagationStopped(); ++it) { eventTargetNode = EventTargetNodeCast(it.current()); evt->setCurrentTarget(eventTargetRespectingSVGTargetRules(eventTargetNode)); eventTargetNode->handleLocalEvents(evt.get(), true); } // dispatch to the actual target node it.toLast(); if (!evt->propagationStopped()) { evt->setEventPhase(Event::AT_TARGET); eventTargetNode = EventTargetNodeCast(it.current()); evt->setCurrentTarget(eventTargetRespectingSVGTargetRules(eventTargetNode)); // We do want capturing event listeners to be invoked here, even though // that violates the specification since Mozilla does it. eventTargetNode->handleLocalEvents(evt.get(), true); eventTargetNode->handleLocalEvents(evt.get(), false); } --it; // ok, now bubble up again (only non-capturing event handlers will be called) // ### recalculate the node chain here? (e.g. if target node moved in document by previous event handlers) // no. the DOM specs says: // The chain of EventTargets from the event target to the top of the tree // is determined before the initial dispatch of the event. // If modifications occur to the tree during event processing, // event flow will proceed based on the initial state of the tree. // // since the initial dispatch is before the capturing phase, // there's no need to recalculate the node chain. // (tobias) if (evt->bubbles()) { evt->setEventPhase(Event::BUBBLING_PHASE); for (; it.current() && !evt->propagationStopped() && !evt->cancelBubble(); --it) { eventTargetNode = EventTargetNodeCast(it.current()); evt->setCurrentTarget(eventTargetRespectingSVGTargetRules(eventTargetNode)); eventTargetNode->handleLocalEvents(evt.get(), false); } it.toFirst(); // Handle window events for bubbling phase, except load events, this quirk is needed // because Mozilla used to never propagate load events at all if (evt->type() != eventNames().loadEvent && it.current()->isDocumentNode() && !evt->propagationStopped() && !evt->cancelBubble()) { evt->setCurrentTarget(EventTargetNodeCast(it.current())); static_cast<Document*>(it.current())->handleWindowEvent(evt.get(), false); } } evt->setCurrentTarget(0); evt->setEventPhase(0); // I guess this is correct, the spec does not seem to say // anything about the default event handler phase. // Now call the post dispatch. postDispatchEventHandler(evt.get(), data); // now we call all default event handlers (this is not part of DOM - it is internal to WebCore) it.toLast(); if (evt->bubbles()) for (; it.current() && !evt->defaultPrevented() && !evt->defaultHandled(); --it) EventTargetNodeCast(it.current())->defaultEventHandler(evt.get()); else if (!evt->defaultPrevented() && !evt->defaultHandled()) EventTargetNodeCast(it.current())->defaultEventHandler(evt.get()); // deref all nodes in chain it.toFirst(); for (; it.current(); ++it) it.current()->deref(); // this may delete us Document::updateDocumentsRendering(); // If tempEvent is true, this means that the DOM implementation // will not be storing a reference to the event, i.e. there is no // way to retrieve it from javascript if a script does not already // have a reference to it in a variable. So there is no need for // the interpreter to keep the event in it's cache Frame* frame = referenceNode->document()->frame(); if (tempEvent && frame && frame->script()->isEnabled()) frame->script()->finishedWithEvent(evt.get()); return !evt->defaultPrevented(); // ### what if defaultPrevented was called before dispatchEvent? }