blob: eb61d41ad1101436c4eae7a3fcc2a2fb8d8282a6 [file] [log] [blame]
/*
* Copyright (C) 1999 Lars Knoll ([email protected])
* (C) 1999 Antti Koivisto ([email protected])
* (C) 2001 Dirk Mueller ([email protected])
* Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
* (C) 2007, 2008 Nikolas Zimmermann <[email protected]>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "config.h"
#include "EventTargetNode.h"
#include "Document.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 "PlatformWheelEvent.h"
#include "ProgressEvent.h"
#include "RegisteredEventListener.h"
#include "ScriptController.h"
#include "TextEvent.h"
#include "WebKitAnimationEvent.h"
#include "WebKitTransitionEvent.h"
#include "WheelEvent.h"
#include <wtf/HashSet.h>
#if ENABLE(DOM_STORAGE)
#include "StorageEvent.h"
#endif
#if ENABLE(SVG)
#include "SVGElementInstance.h"
#include "SVGUseElement.h"
#endif
namespace WebCore {
static HashSet<EventTargetNode*>* gNodesDispatchingSimulatedClicks = 0;
EventTargetNode::EventTargetNode(Document* doc, bool isElement, bool isContainer)
: Node(doc, isElement, isContainer)
, m_regdListeners(0)
{
}
EventTargetNode::~EventTargetNode()
{
if (m_regdListeners && !m_regdListeners->isEmpty() && !inDocument())
document()->unregisterDisconnectedNodeWithEventListeners(this);
delete m_regdListeners;
m_regdListeners = 0;
}
ScriptExecutionContext* EventTargetNode::scriptExecutionContext() const
{
return document();
}
void EventTargetNode::insertedIntoDocument()
{
if (m_regdListeners && !m_regdListeners->isEmpty())
document()->unregisterDisconnectedNodeWithEventListeners(this);
Node::insertedIntoDocument();
}
void EventTargetNode::removedFromDocument()
{
if (m_regdListeners && !m_regdListeners->isEmpty())
document()->registerDisconnectedNodeWithEventListeners(this);
Node::removedFromDocument();
}
void EventTargetNode::willMoveToNewOwnerDocument()
{
if (m_regdListeners && !m_regdListeners->isEmpty())
document()->unregisterDisconnectedNodeWithEventListeners(this);
Node::willMoveToNewOwnerDocument();
}
void EventTargetNode::didMoveToNewOwnerDocument()
{
if (m_regdListeners && !m_regdListeners->isEmpty())
document()->registerDisconnectedNodeWithEventListeners(this);
Node::didMoveToNewOwnerDocument();
}
static inline void updateSVGElementInstancesAfterEventListenerChange(EventTargetNode* referenceNode)
{
ASSERT(referenceNode);
#if ENABLE(SVG)
if (!referenceNode->isSVGElement())
return;
// Elements living inside a <use> shadow tree, never cause any updates!
if (referenceNode->shadowTreeRootNode())
return;
// We're possibly (a child of) an element that is referenced by a <use> client
// If an event listeners changes on a referenced element, update all instances.
for (Node* node = referenceNode; node; node = node->parentNode()) {
if (!node->hasID() || !node->isSVGElement())
continue;
SVGElementInstance::invalidateAllInstancesOfElement(static_cast<SVGElement*>(node));
break;
}
#endif
}
void EventTargetNode::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
{
Document* doc = document();
if (!doc->attached())
return;
doc->addListenerTypeIfNeeded(eventType);
if (!m_regdListeners)
m_regdListeners = new RegisteredEventListenerList;
// Remove existing identical listener set with identical arguments.
// The DOM2 spec says that "duplicate instances are discarded" in this case.
removeEventListener(eventType, listener.get(), useCapture);
// adding the first one
if (m_regdListeners->isEmpty() && !inDocument())
doc->registerDisconnectedNodeWithEventListeners(this);
m_regdListeners->append(RegisteredEventListener::create(eventType, listener, useCapture));
updateSVGElementInstancesAfterEventListenerChange(this);
#if ENABLE(TOUCH_EVENTS) // Android
if (eventType == eventNames().touchstartEvent ||
eventType == eventNames().touchendEvent ||
eventType == eventNames().touchmoveEvent ||
eventType == eventNames().touchcancelEvent)
doc->addTouchEventListener(this);
#endif
}
void EventTargetNode::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
{
if (!m_regdListeners)
return;
RegisteredEventListenerList::Iterator end = m_regdListeners->end();
for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it) {
RegisteredEventListener& r = **it;
if (r.eventType() == eventType && r.listener() == listener && r.useCapture() == useCapture) {
(*it)->setRemoved(true);
it = m_regdListeners->remove(it);
// removed last
if (m_regdListeners->isEmpty() && !inDocument())
document()->unregisterDisconnectedNodeWithEventListeners(this);
updateSVGElementInstancesAfterEventListenerChange(this);
#if ENABLE(TOUCH_EVENTS) // Android
if (eventType == eventNames().touchstartEvent ||
eventType == eventNames().touchendEvent ||
eventType == eventNames().touchmoveEvent ||
eventType == eventNames().touchcancelEvent)
document()->removeTouchEventListener(this);
#endif
return;
}
}
}
void EventTargetNode::removeAllEventListeners()
{
#if ENABLE(TOUCH_EVENTS) // Android
document()->removeTouchEventListener(this);
#endif
delete m_regdListeners;
m_regdListeners = 0;
}
void EventTargetNode::handleLocalEvents(Event *evt, bool useCapture)
{
if (disabled() && evt->isMouseEvent())
return;
if (!m_regdListeners || m_regdListeners->isEmpty())
return;
RegisteredEventListenerList listenersCopy = *m_regdListeners;
RegisteredEventListenerList::Iterator end = listenersCopy.end();
for (RegisteredEventListenerList::Iterator it = listenersCopy.begin(); it != end; ++it) {
if ((*it)->eventType() == evt->type() && (*it)->useCapture() == useCapture && !(*it)->removed())
(*it)->listener()->handleEvent(evt, false);
}
}
#if ENABLE(SVG)
static inline SVGElementInstance* eventTargetAsSVGElementInstance(EventTargetNode* referenceNode)
{
ASSERT(referenceNode);
if (!referenceNode->isSVGElement())
return 0;
// Spec: The event handling for the non-exposed tree works as if the referenced element had been textually included
// as a deeply cloned child of the 'use' element, except that events are dispatched to the SVGElementInstance objects
for (Node* n = referenceNode; n; n = n->parentNode()) {
if (!n->isShadowNode() || !n->isSVGElement())
continue;
Node* shadowTreeParentElement = n->shadowParentNode();
ASSERT(shadowTreeParentElement->hasTagName(SVGNames::useTag));
if (SVGElementInstance* instance = static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode))
return instance;
}
return 0;
}
#endif
static inline EventTarget* eventTargetRespectingSVGTargetRules(EventTargetNode* referenceNode)
{
ASSERT(referenceNode);
#if ENABLE(SVG)
if (SVGElementInstance* instance = eventTargetAsSVGElementInstance(referenceNode)) {
ASSERT(instance->shadowTreeElement() == referenceNode);
return instance;
}
#endif
return referenceNode;
}
bool EventTargetNode::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;
}
evt->setTarget(eventTargetRespectingSVGTargetRules(this));
RefPtr<FrameView> view = document()->view();
return dispatchGenericEvent(evt.release(), ec);
}
bool EventTargetNode::dispatchGenericEvent(PassRefPtr<Event> e, ExceptionCode& ec)
{
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 (inDocument()) {
for (Node* n = this; n; n = n->eventParentNode()) {
#if ENABLE(SVG)
// Skip <use> shadow tree elements
if (n->isSVGElement() && n->isShadowNode())
continue;
#endif
n->ref();
nodeChain.prepend(n);
}
} else {
// if node is not in the document just send event to itself
ref();
nodeChain.prepend(this);
}
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() != this && !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();
return !evt->defaultPrevented(); // ### what if defaultPrevented was called before dispatchEvent?
}
bool EventTargetNode::dispatchSubtreeModifiedEvent()
{
ASSERT(!eventDispatchForbidden());
document()->incDOMTreeVersion();
notifyNodeListsAttributeChanged(); // FIXME: Can do better some day. Really only care about the name attribute changing.
if (!document()->hasListenerType(Document::DOMSUBTREEMODIFIED_LISTENER))
return false;
ExceptionCode ec = 0;
return dispatchEvent(MutationEvent::create(eventNames().DOMSubtreeModifiedEvent, true, false, 0, String(), String(), String(), 0), ec);
}
void EventTargetNode::dispatchWindowEvent(PassRefPtr<Event> e)
{
ASSERT(!eventDispatchForbidden());
RefPtr<Event> evt(e);
RefPtr<Document> doc = document();
evt->setTarget(doc);
doc->handleWindowEvent(evt.get(), true);
doc->handleWindowEvent(evt.get(), false);
}
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);
ExceptionCode ec = 0;
ownerElement->dispatchGenericEvent(ownerEvent.release(), ec);
}
}
}
bool EventTargetNode::dispatchUIEvent(const AtomicString& eventType, int detail, PassRefPtr<Event> underlyingEvent)
{
ASSERT(!eventDispatchForbidden());
ASSERT(eventType == eventNames().DOMFocusInEvent || eventType == eventNames().DOMFocusOutEvent || eventType == eventNames().DOMActivateEvent);
bool cancelable = eventType == eventNames().DOMActivateEvent;
ExceptionCode ec = 0;
RefPtr<UIEvent> evt = UIEvent::create(eventType, true, cancelable, document()->defaultView(), detail);
evt->setUnderlyingEvent(underlyingEvent);
return dispatchEvent(evt.release(), ec);
}
bool EventTargetNode::dispatchKeyEvent(const PlatformKeyboardEvent& key)
{
ASSERT(!eventDispatchForbidden());
ExceptionCode ec = 0;
RefPtr<KeyboardEvent> keyboardEvent = KeyboardEvent::create(key, document()->defaultView());
bool r = dispatchEvent(keyboardEvent, ec);
// we want to return false if default is prevented (already taken care of)
// or if the element is default-handled by the DOM. Otherwise we let it just
// let it get handled by AppKit
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());
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);
}
void EventTargetNode::dispatchSimulatedClick(PassRefPtr<Event> event, bool sendMouseEvents, bool showPressedLook)
{
if (!gNodesDispatchingSimulatedClicks)
gNodesDispatchingSimulatedClicks = new HashSet<EventTargetNode*>;
else if (gNodesDispatchingSimulatedClicks->contains(this))
return;
gNodesDispatchingSimulatedClicks->add(this);
// send mousedown and mouseup before the click, if requested
if (sendMouseEvents)
dispatchSimulatedMouseEvent(eventNames().mousedownEvent, event.get());
setActive(true, showPressedLook);
if (sendMouseEvents)
dispatchSimulatedMouseEvent(eventNames().mouseupEvent, event.get());
setActive(false);
// always send click
dispatchSimulatedMouseEvent(eventNames().clickEvent, event);
gNodesDispatchingSimulatedClicks->remove(this);
}
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;
}
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());
// Convert the deltas from pixels to lines if we have a pixel scroll event.
float deltaX = e.deltaX();
float deltaY = e.deltaY();
// FIXME: Should we do anything with a ScrollByPageWheelEvent here?
// It will be treated like a line scroll of 1 right now.
if (e.granularity() == ScrollByPixelWheelEvent) {
deltaX /= cMouseWheelPixelsPerLineStep;
deltaY /= cMouseWheelPixelsPerLineStep;
}
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))
e.accept();
}
bool EventTargetNode::dispatchWebKitAnimationEvent(const AtomicString& eventType, const String& animationName, double elapsedTime)
{
ASSERT(!eventDispatchForbidden());
ExceptionCode ec = 0;
return dispatchEvent(WebKitAnimationEvent::create(eventType, animationName, elapsedTime), ec);
}
bool EventTargetNode::dispatchWebKitTransitionEvent(const AtomicString& eventType, const String& propertyName, double elapsedTime)
{
ASSERT(!eventDispatchForbidden());
ExceptionCode ec = 0;
return dispatchEvent(WebKitTransitionEvent::create(eventType, propertyName, elapsedTime), ec);
}
void EventTargetNode::dispatchFocusEvent()
{
dispatchEventForType(eventNames().focusEvent, false, false);
}
void EventTargetNode::dispatchBlurEvent()
{
dispatchEventForType(eventNames().blurEvent, false, false);
}
bool EventTargetNode::dispatchEventForType(const AtomicString& eventType, bool canBubbleArg, bool cancelableArg)
{
ASSERT(!eventDispatchForbidden());
ExceptionCode ec = 0;
return dispatchEvent(Event::create(eventType, canBubbleArg, cancelableArg), ec);
}
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);
}
void EventTargetNode::dispatchStorageEvent(const AtomicString &eventType, const String& key, const String& oldValue, const String& newValue, Frame* source)
{
#if ENABLE(DOM_STORAGE)
ASSERT(!eventDispatchForbidden());
ExceptionCode ec = 0;
dispatchEvent(StorageEvent::create(eventType, key, oldValue, newValue, source->document()->documentURI(), source->domWindow()), ec);
#endif
}
void EventTargetNode::removeInlineEventListenerForType(const AtomicString& eventType)
{
if (!m_regdListeners) // nothing to remove
return;
RegisteredEventListenerList::Iterator end = m_regdListeners->end();
for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it) {
EventListener* listener = (*it)->listener();
if ((*it)->eventType() != eventType || !listener->isInline())
continue;
it = m_regdListeners->remove(it);
// removed last
if (m_regdListeners->isEmpty() && !inDocument())
document()->unregisterDisconnectedNodeWithEventListeners(this);
updateSVGElementInstancesAfterEventListenerChange(this);
return;
}
}
void EventTargetNode::setInlineEventListenerForType(const AtomicString& eventType, PassRefPtr<EventListener> listener)
{
// In case we are the only one holding a reference to it, we don't want removeInlineEventListenerForType to destroy it.
removeInlineEventListenerForType(eventType);
if (listener)
addEventListener(eventType, listener, false);
}
void EventTargetNode::setInlineEventListenerForTypeAndAttribute(const AtomicString& eventType, Attribute* attr)
{
setInlineEventListenerForType(eventType, document()->createEventListener(attr->localName().string(), attr->value(), this));
}
EventListener* EventTargetNode::inlineEventListenerForType(const AtomicString& eventType) const
{
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()->isInline())
return (*it)->listener();
return 0;
}
#ifdef ANDROID
EventListener *EventTargetNode::getEventListener(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)
return (*it)->listener();
return 0;
}
#endif
bool EventTargetNode::disabled() const
{
return false;
}
void EventTargetNode::defaultEventHandler(Event* event)
{
if (event->target() != this)
return;
const AtomicString& eventType = event->type();
if (eventType == eventNames().keydownEvent || eventType == eventNames().keypressEvent) {
if (event->isKeyboardEvent())
if (Frame* frame = document()->frame())
frame->eventHandler()->defaultKeyboardEventHandler(static_cast<KeyboardEvent*>(event));
} else if (eventType == eventNames().clickEvent) {
int detail = event->isUIEvent() ? static_cast<UIEvent*>(event)->detail() : 0;
dispatchUIEvent(eventNames().DOMActivateEvent, detail, event);
} else if (eventType == eventNames().contextmenuEvent) {
if (Frame* frame = document()->frame())
if (Page* page = frame->page())
page->contextMenuController()->handleContextMenuEvent(event);
} else if (eventType == eventNames().textInputEvent) {
if (event->isTextEvent())
if (Frame* frame = document()->frame())
frame->eventHandler()->defaultTextInputEventHandler(static_cast<TextEvent*>(event));
}
}
EventListener* EventTargetNode::onabort() const
{
return inlineEventListenerForType(eventNames().abortEvent);
}
void EventTargetNode::setOnabort(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().abortEvent, eventListener);
}
EventListener* EventTargetNode::onblur() const
{
return inlineEventListenerForType(eventNames().blurEvent);
}
void EventTargetNode::setOnblur(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().blurEvent, eventListener);
}
EventListener* EventTargetNode::onchange() const
{
return inlineEventListenerForType(eventNames().changeEvent);
}
void EventTargetNode::setOnchange(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().changeEvent, eventListener);
}
EventListener* EventTargetNode::onclick() const
{
return inlineEventListenerForType(eventNames().clickEvent);
}
void EventTargetNode::setOnclick(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().clickEvent, eventListener);
}
EventListener* EventTargetNode::oncontextmenu() const
{
return inlineEventListenerForType(eventNames().contextmenuEvent);
}
void EventTargetNode::setOncontextmenu(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().contextmenuEvent, eventListener);
}
EventListener* EventTargetNode::ondblclick() const
{
return inlineEventListenerForType(eventNames().dblclickEvent);
}
void EventTargetNode::setOndblclick(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().dblclickEvent, eventListener);
}
EventListener* EventTargetNode::onerror() const
{
return inlineEventListenerForType(eventNames().errorEvent);
}
void EventTargetNode::setOnerror(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().errorEvent, eventListener);
}
EventListener* EventTargetNode::onfocus() const
{
return inlineEventListenerForType(eventNames().focusEvent);
}
void EventTargetNode::setOnfocus(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().focusEvent, eventListener);
}
EventListener* EventTargetNode::oninput() const
{
return inlineEventListenerForType(eventNames().inputEvent);
}
void EventTargetNode::setOninput(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().inputEvent, eventListener);
}
EventListener* EventTargetNode::onkeydown() const
{
return inlineEventListenerForType(eventNames().keydownEvent);
}
void EventTargetNode::setOnkeydown(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().keydownEvent, eventListener);
}
EventListener* EventTargetNode::onkeypress() const
{
return inlineEventListenerForType(eventNames().keypressEvent);
}
void EventTargetNode::setOnkeypress(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().keypressEvent, eventListener);
}
EventListener* EventTargetNode::onkeyup() const
{
return inlineEventListenerForType(eventNames().keyupEvent);
}
void EventTargetNode::setOnkeyup(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().keyupEvent, eventListener);
}
EventListener* EventTargetNode::onload() const
{
return inlineEventListenerForType(eventNames().loadEvent);
}
void EventTargetNode::setOnload(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().loadEvent, eventListener);
}
EventListener* EventTargetNode::onmousedown() const
{
return inlineEventListenerForType(eventNames().mousedownEvent);
}
void EventTargetNode::setOnmousedown(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().mousedownEvent, eventListener);
}
EventListener* EventTargetNode::onmousemove() const
{
return inlineEventListenerForType(eventNames().mousemoveEvent);
}
void EventTargetNode::setOnmousemove(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().mousemoveEvent, eventListener);
}
EventListener* EventTargetNode::onmouseout() const
{
return inlineEventListenerForType(eventNames().mouseoutEvent);
}
void EventTargetNode::setOnmouseout(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().mouseoutEvent, eventListener);
}
EventListener* EventTargetNode::onmouseover() const
{
return inlineEventListenerForType(eventNames().mouseoverEvent);
}
void EventTargetNode::setOnmouseover(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().mouseoverEvent, eventListener);
}
EventListener* EventTargetNode::onmouseup() const
{
return inlineEventListenerForType(eventNames().mouseupEvent);
}
void EventTargetNode::setOnmouseup(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().mouseupEvent, eventListener);
}
EventListener* EventTargetNode::onmousewheel() const
{
return inlineEventListenerForType(eventNames().mousewheelEvent);
}
void EventTargetNode::setOnmousewheel(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().mousewheelEvent, eventListener);
}
EventListener* EventTargetNode::onbeforecut() const
{
return inlineEventListenerForType(eventNames().beforecutEvent);
}
void EventTargetNode::setOnbeforecut(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().beforecutEvent, eventListener);
}
EventListener* EventTargetNode::oncut() const
{
return inlineEventListenerForType(eventNames().cutEvent);
}
void EventTargetNode::setOncut(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().cutEvent, eventListener);
}
EventListener* EventTargetNode::onbeforecopy() const
{
return inlineEventListenerForType(eventNames().beforecopyEvent);
}
void EventTargetNode::setOnbeforecopy(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().beforecopyEvent, eventListener);
}
EventListener* EventTargetNode::oncopy() const
{
return inlineEventListenerForType(eventNames().copyEvent);
}
void EventTargetNode::setOncopy(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().copyEvent, eventListener);
}
EventListener* EventTargetNode::onbeforepaste() const
{
return inlineEventListenerForType(eventNames().beforepasteEvent);
}
void EventTargetNode::setOnbeforepaste(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().beforepasteEvent, eventListener);
}
EventListener* EventTargetNode::onpaste() const
{
return inlineEventListenerForType(eventNames().pasteEvent);
}
void EventTargetNode::setOnpaste(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().pasteEvent, eventListener);
}
EventListener* EventTargetNode::ondragenter() const
{
return inlineEventListenerForType(eventNames().dragenterEvent);
}
void EventTargetNode::setOndragenter(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().dragenterEvent, eventListener);
}
EventListener* EventTargetNode::ondragover() const
{
return inlineEventListenerForType(eventNames().dragoverEvent);
}
void EventTargetNode::setOndragover(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().dragoverEvent, eventListener);
}
EventListener* EventTargetNode::ondragleave() const
{
return inlineEventListenerForType(eventNames().dragleaveEvent);
}
void EventTargetNode::setOndragleave(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().dragleaveEvent, eventListener);
}
EventListener* EventTargetNode::ondrop() const
{
return inlineEventListenerForType(eventNames().dropEvent);
}
void EventTargetNode::setOndrop(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().dropEvent, eventListener);
}
EventListener* EventTargetNode::ondragstart() const
{
return inlineEventListenerForType(eventNames().dragstartEvent);
}
void EventTargetNode::setOndragstart(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().dragstartEvent, eventListener);
}
EventListener* EventTargetNode::ondrag() const
{
return inlineEventListenerForType(eventNames().dragEvent);
}
void EventTargetNode::setOndrag(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().dragEvent, eventListener);
}
EventListener* EventTargetNode::ondragend() const
{
return inlineEventListenerForType(eventNames().dragendEvent);
}
void EventTargetNode::setOndragend(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().dragendEvent, eventListener);
}
EventListener* EventTargetNode::onreset() const
{
return inlineEventListenerForType(eventNames().resetEvent);
}
void EventTargetNode::setOnreset(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().resetEvent, eventListener);
}
EventListener* EventTargetNode::onresize() const
{
return inlineEventListenerForType(eventNames().resizeEvent);
}
void EventTargetNode::setOnresize(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().resizeEvent, eventListener);
}
EventListener* EventTargetNode::onscroll() const
{
return inlineEventListenerForType(eventNames().scrollEvent);
}
void EventTargetNode::setOnscroll(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().scrollEvent, eventListener);
}
EventListener* EventTargetNode::onsearch() const
{
return inlineEventListenerForType(eventNames().searchEvent);
}
void EventTargetNode::setOnsearch(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().searchEvent, eventListener);
}
EventListener* EventTargetNode::onselect() const
{
return inlineEventListenerForType(eventNames().selectEvent);
}
void EventTargetNode::setOnselect(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().selectEvent, eventListener);
}
EventListener* EventTargetNode::onselectstart() const
{
return inlineEventListenerForType(eventNames().selectstartEvent);
}
void EventTargetNode::setOnselectstart(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().selectstartEvent, eventListener);
}
EventListener* EventTargetNode::onsubmit() const
{
return inlineEventListenerForType(eventNames().submitEvent);
}
void EventTargetNode::setOnsubmit(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().submitEvent, eventListener);
}
EventListener* EventTargetNode::onunload() const
{
return inlineEventListenerForType(eventNames().unloadEvent);
}
void EventTargetNode::setOnunload(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().unloadEvent, eventListener);
}
#if ENABLE(TOUCH_EVENTS) // Android
EventListener* EventTargetNode::ontouchstart() const
{
return inlineEventListenerForType(eventNames().touchstartEvent);
}
void EventTargetNode::setOntouchstart(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().touchstartEvent, eventListener);
}
EventListener* EventTargetNode::ontouchend() const
{
return inlineEventListenerForType(eventNames().touchendEvent);
}
void EventTargetNode::setOntouchend(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().touchendEvent, eventListener);
}
EventListener* EventTargetNode::ontouchmove() const
{
return inlineEventListenerForType(eventNames().touchmoveEvent);
}
void EventTargetNode::setOntouchmove(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().touchmoveEvent, eventListener);
}
EventListener* EventTargetNode::ontouchcancel() const
{
return inlineEventListenerForType(eventNames().touchcancelEvent);
}
void EventTargetNode::setOntouchcancel(PassRefPtr<EventListener> eventListener)
{
setInlineEventListenerForType(eventNames().touchcancelEvent, eventListener);
}
#endif
} // namespace WebCore