EventDispatcher.cpp [plain text]
#include "config.h"
#include "EventDispatcher.h"
#include "ContainerNode.h"
#include "ElementShadow.h"
#include "EventContext.h"
#include "EventDispatchMediator.h"
#include "EventPathWalker.h"
#include "EventRetargeter.h"
#include "FrameView.h"
#include "HTMLMediaElement.h"
#include "InsertionPoint.h"
#include "InspectorInstrumentation.h"
#include "MouseEvent.h"
#include "ScopedEventQueue.h"
#include "ShadowRoot.h"
#include "WindowEventContext.h"
#include <wtf/RefPtr.h>
namespace WebCore {
bool EventDispatcher::dispatchEvent(Node* node, PassRefPtr<EventDispatchMediator> mediator)
{
ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
if (!mediator->event())
return true;
EventDispatcher dispatcher(node, mediator->event());
return mediator->dispatchEvent(&dispatcher);
}
EventDispatcher::EventDispatcher(Node* node, PassRefPtr<Event> event)
: m_node(node)
, m_event(event)
#ifndef NDEBUG
, m_eventDispatched(false)
#endif
{
ASSERT(node);
ASSERT(m_event.get());
ASSERT(!m_event->type().isNull()); m_view = node->document()->view();
EventRetargeter::calculateEventPath(m_node.get(), m_event.get(), m_eventPath);
}
void EventDispatcher::dispatchScopedEvent(Node* node, PassRefPtr<EventDispatchMediator> mediator)
{
mediator->event()->setTarget(EventRetargeter::eventTargetRespectingTargetRules(node));
ScopedEventQueue::instance()->enqueueEventDispatchMediator(mediator);
}
void EventDispatcher::dispatchSimulatedClick(Element* element, Event* underlyingEvent, SimulatedClickMouseEventOptions mouseEventOptions, SimulatedClickVisualOptions visualOptions)
{
if (element->isDisabledFormControl())
return;
DEFINE_STATIC_LOCAL(HashSet<Element*>, elementsDispatchingSimulatedClicks, ());
if (!elementsDispatchingSimulatedClicks.add(element).isNewEntry)
return;
if (mouseEventOptions == SendMouseOverUpDownEvents)
EventDispatcher(element, SimulatedMouseEvent::create(eventNames().mouseoverEvent, element->document()->defaultView(), underlyingEvent)).dispatch();
if (mouseEventOptions != SendNoEvents)
EventDispatcher(element, SimulatedMouseEvent::create(eventNames().mousedownEvent, element->document()->defaultView(), underlyingEvent)).dispatch();
element->setActive(true, visualOptions == ShowPressedLook);
if (mouseEventOptions != SendNoEvents)
EventDispatcher(element, SimulatedMouseEvent::create(eventNames().mouseupEvent, element->document()->defaultView(), underlyingEvent)).dispatch();
element->setActive(false);
EventDispatcher(element, SimulatedMouseEvent::create(eventNames().clickEvent, element->document()->defaultView(), underlyingEvent)).dispatch();
elementsDispatchingSimulatedClicks.remove(element);
}
bool EventDispatcher::dispatch()
{
#ifndef NDEBUG
ASSERT(!m_eventDispatched);
m_eventDispatched = true;
#endif
ChildNodesLazySnapshot::takeChildNodesLazySnapshot();
m_event->setTarget(EventRetargeter::eventTargetRespectingTargetRules(m_node.get()));
ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
ASSERT(m_event->target());
WindowEventContext windowEventContext(m_event.get(), m_node.get(), topEventContext());
InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEvent(m_node->document(), *m_event, windowEventContext.window(), m_node.get(), m_eventPath);
void* preDispatchEventHandlerResult;
if (dispatchEventPreProcess(preDispatchEventHandlerResult) == ContinueDispatching)
if (dispatchEventAtCapturing(windowEventContext) == ContinueDispatching)
if (dispatchEventAtTarget() == ContinueDispatching)
dispatchEventAtBubbling(windowEventContext);
dispatchEventPostProcess(preDispatchEventHandlerResult);
m_event->setTarget(windowEventContext.target());
m_event->setCurrentTarget(0);
InspectorInstrumentation::didDispatchEvent(cookie);
return !m_event->defaultPrevented();
}
inline EventDispatchContinuation EventDispatcher::dispatchEventPreProcess(void*& preDispatchEventHandlerResult)
{
preDispatchEventHandlerResult = m_node->preDispatchEventHandler(m_event.get());
return (m_eventPath.isEmpty() || m_event->propagationStopped()) ? DoneDispatching : ContinueDispatching;
}
inline EventDispatchContinuation EventDispatcher::dispatchEventAtCapturing(WindowEventContext& windowEventContext)
{
m_event->setEventPhase(Event::CAPTURING_PHASE);
if (windowEventContext.handleLocalEvents(m_event.get()) && m_event->propagationStopped())
return DoneDispatching;
for (size_t i = m_eventPath.size() - 1; i > 0; --i) {
const EventContext& eventContext = *m_eventPath[i];
if (eventContext.currentTargetSameAsTarget())
continue;
eventContext.handleLocalEvents(m_event.get());
if (m_event->propagationStopped())
return DoneDispatching;
}
return ContinueDispatching;
}
inline EventDispatchContinuation EventDispatcher::dispatchEventAtTarget()
{
m_event->setEventPhase(Event::AT_TARGET);
m_eventPath[0]->handleLocalEvents(m_event.get());
return m_event->propagationStopped() ? DoneDispatching : ContinueDispatching;
}
inline void EventDispatcher::dispatchEventAtBubbling(WindowEventContext& windowContext)
{
size_t size = m_eventPath.size();
for (size_t i = 1; i < size; ++i) {
const EventContext& eventContext = *m_eventPath[i];
if (eventContext.currentTargetSameAsTarget())
m_event->setEventPhase(Event::AT_TARGET);
else if (m_event->bubbles() && !m_event->cancelBubble())
m_event->setEventPhase(Event::BUBBLING_PHASE);
else
continue;
eventContext.handleLocalEvents(m_event.get());
if (m_event->propagationStopped())
return;
}
if (m_event->bubbles() && !m_event->cancelBubble()) {
m_event->setEventPhase(Event::BUBBLING_PHASE);
windowContext.handleLocalEvents(m_event.get());
}
}
inline void EventDispatcher::dispatchEventPostProcess(void* preDispatchEventHandlerResult)
{
m_event->setTarget(EventRetargeter::eventTargetRespectingTargetRules(m_node.get()));
m_event->setCurrentTarget(0);
m_event->setEventPhase(0);
m_node->postDispatchEventHandler(m_event.get(), preDispatchEventHandlerResult);
if (!m_event->defaultPrevented() && !m_event->defaultHandled()) {
m_node->defaultEventHandler(m_event.get());
ASSERT(!m_event->defaultPrevented());
if (m_event->defaultHandled())
return;
if (m_event->bubbles()) {
size_t size = m_eventPath.size();
for (size_t i = 1; i < size; ++i) {
m_eventPath[i]->node()->defaultEventHandler(m_event.get());
ASSERT(!m_event->defaultPrevented());
if (m_event->defaultHandled())
return;
}
}
}
}
const EventContext* EventDispatcher::topEventContext()
{
return m_eventPath.isEmpty() ? 0 : m_eventPath.last().get();
}
}