EventTargetNode.cpp [plain text]
#include "config.h"
#include "EventTargetNode.h"
#include "Document.h"
#include "Event.h"
#include "EventException.h"
#include "EventHandler.h"
#include "EventListener.h"
#include "EventNames.h"
#include "Frame.h"
#include "FrameView.h"
#include "KeyboardEvent.h"
#include "MouseEvent.h"
#include "MutationEvent.h"
#include "Page.h"
#include "PlatformMouseEvent.h"
#include "PlatformTouchEvent.h"
#include "PlatformWheelEvent.h"
#include "ProgressEvent.h"
#include "RegisteredEventListener.h"
#include "TextEvent.h"
#include "TextStream.h"
#include "WebKitAnimationEvent.h"
#include "WebKitTransitionEvent.h"
#include "WheelEvent.h"
#include "WebCoreThread.h"
#include "TouchEvent.h"
namespace WebCore {
using namespace EventNames;
HashMap<Node *, int> * EventTargetNode::WebThreadGetCurrentDOMMouseWheelEventListeners()
{
WebThreadContext *threadContext = WebThreadCurrentContext();
if (!threadContext->DOMMouseWheelEventListeners)
threadContext->DOMMouseWheelEventListeners = new HashMap<Node *, int>;
return static_cast< HashMap<Node *, int> *>(threadContext->DOMMouseWheelEventListeners);
}
HashMap<Node *, int> * EventTargetNode::WebThreadGetCurrentDOMMouseMoveEventListeners()
{
WebThreadContext *threadContext = WebThreadCurrentContext();
if (!threadContext->DOMMouseMoveEventListeners)
threadContext->DOMMouseMoveEventListeners = new HashMap<Node *, int>;
return static_cast< HashMap<Node *, int> *>(threadContext->DOMMouseMoveEventListeners);
}
HashMap<Node *, int> * EventTargetNode::WebThreadGetCurrentDOMMouseClickEventListeners()
{
WebThreadContext *threadContext = WebThreadCurrentContext();
if (!threadContext->DOMMouseClickEventListeners)
threadContext->DOMMouseClickEventListeners = new HashMap<Node *, int>;
return static_cast< HashMap<Node *, int> *>(threadContext->DOMMouseClickEventListeners);
}
EventTargetNode::EventTargetNode(Document *doc)
: Node(doc)
, m_regdListeners(0)
{
}
EventTargetNode::~EventTargetNode()
{
WebThreadGetCurrentDOMMouseMoveEventListeners()->remove(this);
WebThreadGetCurrentDOMMouseWheelEventListeners()->remove(this);
WebThreadGetCurrentDOMMouseClickEventListeners()->remove(this);
if (m_regdListeners && !m_regdListeners->isEmpty() && !inDocument())
document()->unregisterDisconnectedNodeWithEventListeners(this);
delete m_regdListeners;
m_regdListeners = 0;
}
void EventTargetNode::insertedIntoDocument()
{
EventTarget::insertedIntoDocument(this);
Node::insertedIntoDocument();
}
void EventTargetNode::removedFromDocument()
{
EventTarget::removedFromDocument(this);
Node::removedFromDocument();
}
void EventTargetNode::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
{
EventTarget::addEventListener(this, eventType, listener, useCapture);
}
void EventTargetNode::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
{
EventTarget::removeEventListener(this, eventType, listener, useCapture);
}
void EventTargetNode::removeAllEventListeners()
{
EventTarget::removeAllEventListeners(this);
}
void EventTargetNode::handleLocalEvents(Event *evt, bool useCapture)
{
if (disabled() && evt->isMouseEvent())
return;
EventTarget::handleLocalEvents(this, evt, useCapture);
}
bool EventTargetNode::dispatchEvent(PassRefPtr<Event> e, ExceptionCode& ec, bool tempEvent)
{
RefPtr<Event> evt(e);
ASSERT(!eventDispatchForbidden());
if (!evt || evt->type().isEmpty()) {
ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
return false;
}
EventTargetNode* eventTarget = this;
evt->setTarget(eventTargetRespectingSVGTargetRules(eventTarget));
RefPtr<FrameView> view = document()->view();
return dispatchGenericEvent(eventTarget, evt.release(), ec, tempEvent);
}
bool EventTargetNode::dispatchSubtreeModifiedEvent(bool sendChildrenChanged)
{
ASSERT(!eventDispatchForbidden());
document()->incDOMTreeVersion();
if (sendChildrenChanged)
childrenChanged();
else
notifyNodeListsAttributeChanged();
if (!document()->hasListenerType(Document::DOMSUBTREEMODIFIED_LISTENER))
return false;
ExceptionCode ec = 0;
return dispatchEvent(new MutationEvent(DOMSubtreeModifiedEvent,
true,false,0,String(),String(),String(),0),ec,true);
}
void EventTargetNode::dispatchWindowEvent(const AtomicString &eventType, bool canBubbleArg, bool cancelableArg)
{
ASSERT(!eventDispatchForbidden());
ExceptionCode ec = 0;
RefPtr<Event> evt = new Event(eventType, canBubbleArg, cancelableArg);
RefPtr<Document> doc = document();
evt->setTarget(doc);
doc->handleWindowEvent(evt.get(), true);
doc->handleWindowEvent(evt.get(), false);
if (eventType == loadEvent) {
Element* ownerElement = doc->ownerElement();
if (ownerElement) {
RefPtr<Event> ownerEvent = new Event(eventType, false, cancelableArg);
ownerEvent->setTarget(ownerElement);
ownerElement->dispatchGenericEvent(ownerElement, ownerEvent.release(), ec, true);
}
}
}
bool EventTargetNode::dispatchUIEvent(const AtomicString& eventType, int detail, PassRefPtr<Event> underlyingEvent)
{
ASSERT(!eventDispatchForbidden());
ASSERT(eventType == DOMFocusInEvent || eventType == DOMFocusOutEvent || eventType == DOMActivateEvent);
bool cancelable = eventType == DOMActivateEvent;
ExceptionCode ec = 0;
RefPtr<UIEvent> evt = new UIEvent(eventType, true, cancelable, document()->defaultView(), detail);
evt->setUnderlyingEvent(underlyingEvent);
return dispatchEvent(evt.release(), ec, true);
}
bool EventTargetNode::dispatchKeyEvent(const PlatformKeyboardEvent& key)
{
ASSERT(!eventDispatchForbidden());
ExceptionCode ec = 0;
RefPtr<KeyboardEvent> keyboardEvent = new KeyboardEvent(key, document()->defaultView());
bool r = dispatchEvent(keyboardEvent,ec,true);
if (keyboardEvent->defaultHandled())
r = false;
return r;
}
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::dispatchSimulatedMouseEvent(const AtomicString& eventType,
PassRefPtr<Event> underlyingEvent)
{
ASSERT(!eventDispatchForbidden());
if (m_dispatchingSimulatedEvent)
return;
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();
}
m_dispatchingSimulatedEvent = true;
dispatchMouseEvent(eventType, 0, 0, 0, 0, 0, 0,
ctrlKey, altKey, shiftKey, metaKey, true, 0, underlyingEvent);
m_dispatchingSimulatedEvent = false;
}
void EventTargetNode::dispatchSimulatedClick(PassRefPtr<Event> event, bool sendMouseEvents, bool showPressedLook)
{
if (m_dispatchingSimulatedEvent)
return;
if (sendMouseEvents)
dispatchSimulatedMouseEvent(mousedownEvent, event.get());
setActive(true, showPressedLook);
if (sendMouseEvents)
dispatchSimulatedMouseEvent(mouseupEvent, event.get());
setActive(false);
dispatchSimulatedMouseEvent(clickEvent, event);
}
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()) return true;
if (eventType.isEmpty())
return false;
RefPtr<Node> protect(this);
bool cancelable = eventType != mousemoveEvent;
ExceptionCode ec = 0;
bool swallowEvent = false;
RefPtr<EventTargetNode> relatedTarget = (relatedTargetArg && relatedTargetArg->isEventTargetNode())
? static_cast<EventTargetNode*>(relatedTargetArg) : 0;
RefPtr<Event> mouseEvent = new MouseEvent(eventType,
true, cancelable, document()->defaultView(),
detail, screenX, screenY, pageX, pageY,
ctrlKey, altKey, shiftKey, metaKey, button,
relatedTarget.get(), 0, isSimulated);
mouseEvent->setUnderlyingEvent(underlyingEvent.get());
dispatchEvent(mouseEvent, ec, true);
bool defaultHandled = mouseEvent->defaultHandled();
bool defaultPrevented = mouseEvent->defaultPrevented();
if (defaultHandled || defaultPrevented)
swallowEvent = true;
if (eventType == clickEvent && detail == 2) {
RefPtr<Event> doubleClickEvent = new MouseEvent(dblclickEvent,
true, cancelable, document()->defaultView(),
detail, screenX, screenY, pageX, pageY,
ctrlKey, altKey, shiftKey, metaKey, button,
relatedTarget.get(), 0, isSimulated);
doubleClickEvent->setUnderlyingEvent(underlyingEvent.get());
if (defaultHandled)
doubleClickEvent->setDefaultHandled();
dispatchEvent(doubleClickEvent, ec, true);
if (doubleClickEvent->defaultHandled() || doubleClickEvent->defaultPrevented())
swallowEvent = true;
}
return swallowEvent;
}
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 = new WheelEvent(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, ec, true))
e.accept();
}
bool EventTargetNode::dispatchWebKitAnimationEvent(const AtomicString& eventType, const String& animationName, double elapsedTime)
{
ASSERT(!eventDispatchForbidden());
RefPtr<WebKitAnimationEvent> animEvent = new WebKitAnimationEvent(eventType, animationName, elapsedTime);
ExceptionCode ec = 0;
return dispatchEvent(animEvent, ec, true);
}
bool EventTargetNode::dispatchWebKitTransitionEvent(const AtomicString& eventType, const String& propertyName, double elapsedTime)
{
ASSERT(!eventDispatchForbidden());
RefPtr<WebKitTransitionEvent> transitionEvent = new WebKitTransitionEvent(eventType, propertyName, elapsedTime);
ExceptionCode ec = 0;
return dispatchEvent(transitionEvent, ec, true);
}
void EventTargetNode::dispatchFocusEvent()
{
dispatchHTMLEvent(focusEvent, false, false);
}
void EventTargetNode::dispatchBlurEvent()
{
dispatchHTMLEvent(blurEvent, false, false);
}
bool EventTargetNode::dispatchHTMLEvent(const AtomicString &eventType, bool canBubbleArg, bool cancelableArg)
{
ASSERT(!eventDispatchForbidden());
ExceptionCode ec = 0;
return dispatchEvent(new Event(eventType, canBubbleArg, cancelableArg), ec, true);
}
bool EventTargetNode::dispatchProgressEvent(const AtomicString &eventType, bool lengthComputableArg, unsigned loadedArg, unsigned totalArg)
{
ASSERT(!eventDispatchForbidden());
ExceptionCode ec = 0;
return dispatchEvent(new ProgressEvent(eventType, lengthComputableArg, loadedArg, totalArg), ec, true);
}
void EventTargetNode::removeHTMLEventListener(const AtomicString &eventType)
{
if (!m_regdListeners) return;
RegisteredEventListenerList::Iterator end = m_regdListeners->end();
for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it)
if ((*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener()) {
it = m_regdListeners->remove(it);
if (m_regdListeners->isEmpty() && !inDocument())
document()->unregisterDisconnectedNodeWithEventListeners(this);
return;
}
}
void EventTargetNode::setHTMLEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener)
{
removeHTMLEventListener(eventType);
if (listener)
addEventListener(eventType, listener.get(), false);
}
EventListener *EventTargetNode::getHTMLEventListener(const AtomicString &eventType)
{
if (!m_regdListeners)
return 0;
RegisteredEventListenerList::Iterator end = m_regdListeners->end();
for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it)
if ((*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener())
return (*it)->listener();
return 0;
}
bool EventTargetNode::disabled() const
{
return false;
}
void EventTargetNode::defaultEventHandler(Event* event)
{
if (event->target() != this)
return;
const AtomicString& eventType = event->type();
if (eventType == keydownEvent || eventType == keypressEvent) {
if (event->isKeyboardEvent())
if (Frame* frame = document()->frame())
frame->eventHandler()->defaultKeyboardEventHandler(static_cast<KeyboardEvent*>(event));
} else if (eventType == clickEvent) {
int detail = event->isUIEvent() ? static_cast<UIEvent*>(event)->detail() : 0;
dispatchUIEvent(DOMActivateEvent, detail, event);
} else if (eventType == contextmenuEvent) {
if (Frame* frame = document()->frame())
if (Page* page = frame->page())
page->contextMenuController()->handleContextMenuEvent(event);
} else if (eventType == textInputEvent) {
if (event->isTextEvent())
if (Frame* frame = document()->frame())
frame->eventHandler()->defaultTextInputEventHandler(static_cast<TextEvent*>(event));
}
}
#ifndef NDEBUG
void EventTargetNode::dump(TextStream* stream, DeprecatedString ind) const
{
if (m_regdListeners)
*stream << " #regdListeners=" << m_regdListeners->count();
Node::dump(stream,ind);
}
#endif
bool EventTargetNode::willRespondToMouseMoveEvents()
{
return Node::willRespondToMouseMoveEvents() || WebThreadGetCurrentDOMMouseMoveEventListeners()->contains(this);
}
bool EventTargetNode::willRespondToMouseWheelEvents()
{
return Node::willRespondToMouseWheelEvents() || WebThreadGetCurrentDOMMouseWheelEventListeners()->contains(this);
}
bool EventTargetNode::willRespondToMouseClickEvents()
{
return Node::willRespondToMouseClickEvents() || WebThreadGetCurrentDOMMouseClickEventListeners()->contains(this);
}
}