summaryrefslogtreecommitdiffstats
path: root/WebCore/dom/Node.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/dom/Node.cpp')
-rw-r--r--WebCore/dom/Node.cpp1258
1 files changed, 1232 insertions, 26 deletions
diff --git a/WebCore/dom/Node.cpp b/WebCore/dom/Node.cpp
index eb591a7..bd8f497 100644
--- a/WebCore/dom/Node.cpp
+++ b/WebCore/dom/Node.cpp
@@ -2,7 +2,7 @@
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2001 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
*
* This library is free software; you can redistribute it and/or
@@ -44,25 +44,55 @@
#include "Document.h"
#include "DynamicNodeList.h"
#include "Element.h"
+#include "Event.h"
+#include "EventException.h"
+#include "EventHandler.h"
+#include "EventListener.h"
+#include "EventNames.h"
#include "ExceptionCode.h"
#include "Frame.h"
+#include "FrameView.h"
#include "HTMLNames.h"
#include "JSDOMBinding.h"
+#include "KeyboardEvent.h"
#include "Logging.h"
+#include "MouseEvent.h"
+#include "MutationEvent.h"
#include "NameNodeList.h"
#include "NamedAttrMap.h"
#include "NodeRareData.h"
+#include "Page.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformWheelEvent.h"
#include "ProcessingInstruction.h"
+#include "ProgressEvent.h"
+#include "RegisteredEventListener.h"
#include "RenderObject.h"
#include "ScriptController.h"
#include "SelectorNodeList.h"
#include "StringBuilder.h"
#include "TagNodeList.h"
#include "Text.h"
+#include "TextEvent.h"
+#include "UIEvent.h"
+#include "UIEventWithKeyState.h"
+#include "WebKitAnimationEvent.h"
+#include "WebKitTransitionEvent.h"
+#include "WheelEvent.h"
#include "XMLNames.h"
#include "htmlediting.h"
+#include <wtf/HashSet.h>
#include <wtf/RefCountedLeakCounter.h>
+#if ENABLE(DOM_STORAGE)
+#include "StorageEvent.h"
+#endif
+
+#if ENABLE(SVG)
+#include "SVGElementInstance.h"
+#include "SVGUseElement.h"
+#endif
+
#define DUMP_NODE_STATISTICS 0
using namespace std;
@@ -71,6 +101,8 @@ namespace WebCore {
using namespace HTMLNames;
+static HashSet<Node*>* gNodesDispatchingSimulatedClicks = 0;
+
bool Node::isSupported(const String& feature, const String& version)
{
return DOMImplementation::hasFeature(feature, version);
@@ -255,9 +287,9 @@ Node::StyleChange Node::diff( RenderStyle *s1, RenderStyle *s2 )
// style in cases where you need to.
StyleChange ch = NoInherit;
EDisplay display1 = s1 ? s1->display() : NONE;
- bool fl1 = s1 && s1->hasPseudoStyle(RenderStyle::FIRST_LETTER);
+ bool fl1 = s1 && s1->hasPseudoStyle(FIRST_LETTER);
EDisplay display2 = s2 ? s2->display() : NONE;
- bool fl2 = s2 && s2->hasPseudoStyle(RenderStyle::FIRST_LETTER);
+ bool fl2 = s2 && s2->hasPseudoStyle(FIRST_LETTER);
if (display1 != display2 || fl1 != fl2 || (s1 && s2 && !s1->contentDataEquivalent(s2)))
ch = Detach;
@@ -270,21 +302,21 @@ Node::StyleChange Node::diff( RenderStyle *s1, RenderStyle *s2 )
// If the pseudoStyles have changed, we want any StyleChange that is not NoChange
// because setStyle will do the right thing with anything else.
- if (ch == NoChange && s1->hasPseudoStyle(RenderStyle::BEFORE)) {
- RenderStyle* ps2 = s2->getCachedPseudoStyle(RenderStyle::BEFORE);
+ if (ch == NoChange && s1->hasPseudoStyle(BEFORE)) {
+ RenderStyle* ps2 = s2->getCachedPseudoStyle(BEFORE);
if (!ps2)
ch = NoInherit;
else {
- RenderStyle* ps1 = s1->getCachedPseudoStyle(RenderStyle::BEFORE);
+ RenderStyle* ps1 = s1->getCachedPseudoStyle(BEFORE);
ch = ps1 && *ps1 == *ps2 ? NoChange : NoInherit;
}
}
- if (ch == NoChange && s1->hasPseudoStyle(RenderStyle::AFTER)) {
- RenderStyle* ps2 = s2->getCachedPseudoStyle(RenderStyle::AFTER);
+ if (ch == NoChange && s1->hasPseudoStyle(AFTER)) {
+ RenderStyle* ps2 = s2->getCachedPseudoStyle(AFTER);
if (!ps2)
ch = NoInherit;
else {
- RenderStyle* ps1 = s1->getCachedPseudoStyle(RenderStyle::AFTER);
+ RenderStyle* ps1 = s1->getCachedPseudoStyle(AFTER);
ch = ps2 && *ps1 == *ps2 ? NoChange : NoInherit;
}
}
@@ -348,6 +380,9 @@ Node::~Node()
liveNodeSet.remove(this);
#endif
+ if (!eventListeners().isEmpty() && !inDocument())
+ document()->unregisterDisconnectedNodeWithEventListeners(this);
+
if (!hasRareData())
ASSERT(!NodeRareData::rareDataMap().contains(this));
else {
@@ -583,7 +618,12 @@ bool Node::shouldUseInputMethod() const
RenderBox* Node::renderBox() const
{
- return m_renderer && m_renderer->isBox() ? static_cast<RenderBox*>(m_renderer) : 0;
+ return m_renderer && m_renderer->isBox() ? toRenderBox(m_renderer) : 0;
+}
+
+RenderBoxModelObject* Node::renderBoxModelObject() const
+{
+ return m_renderer && m_renderer->isBoxModelObject() ? toRenderBoxModelObject(m_renderer) : 0;
}
IntRect Node::getRect() const
@@ -1081,21 +1121,6 @@ void Node::detach()
m_inDetach = false;
}
-void Node::insertedIntoDocument()
-{
- setInDocument(true);
- insertedIntoTree(false);
-}
-
-void Node::removedFromDocument()
-{
- if (m_document && m_document->getCSSTarget() == this)
- m_document->setCSSTarget(0);
-
- setInDocument(false);
- removedFromTree(false);
-}
-
Node *Node::previousEditable() const
{
Node *node = previousLeafNode();
@@ -1317,7 +1342,7 @@ bool Node::isBlockFlow() const
bool Node::isBlockFlowOrBlockTable() const
{
- return renderer() && (renderer()->isBlockFlow() || renderer()->isTable() && !renderer()->isInline());
+ return renderer() && (renderer()->isBlockFlow() || (renderer()->isTable() && !renderer()->isInline()));
}
bool Node::isEditableBlock() const
@@ -1984,6 +2009,36 @@ unsigned short Node::compareDocumentPosition(Node* otherNode)
DOCUMENT_POSITION_PRECEDING | DOCUMENT_POSITION_CONTAINS;
}
+FloatPoint Node::convertToPage(const FloatPoint& p) const
+{
+ // If there is a renderer, just ask it to do the conversion
+ if (renderer())
+ return renderer()->localToAbsolute(p, false, true);
+
+ // Otherwise go up the tree looking for a renderer
+ Element *parent = ancestorElement();
+ if (parent)
+ return parent->convertToPage(p);
+
+ // No parent - no conversion needed
+ return p;
+}
+
+FloatPoint Node::convertFromPage(const FloatPoint& p) const
+{
+ // If there is a renderer, just ask it to do the conversion
+ if (renderer())
+ return renderer()->absoluteToLocal(p, false, true);
+
+ // Otherwise go up the tree looking for a renderer
+ Element *parent = ancestorElement();
+ if (parent)
+ return parent->convertFromPage(p);
+
+ // No parent - no conversion needed
+ return p;
+}
+
#if !defined(NDEBUG) || defined(ANDROID_DOM_LOGGING)
static void appendAttributeDesc(const Node* node, String& string, const QualifiedName& name, const char* attrDesc)
@@ -2177,6 +2232,1157 @@ size_t Node::reportDOMNodesSize()
// --------
+ScriptExecutionContext* Node::scriptExecutionContext() const
+{
+ return document();
+}
+
+const RegisteredEventListenerVector& Node::eventListeners() const
+{
+ if (hasRareData()) {
+ if (RegisteredEventListenerVector* listeners = rareData()->listeners())
+ return *listeners;
+ }
+ static const RegisteredEventListenerVector* emptyListenersVector = new RegisteredEventListenerVector;
+ return *emptyListenersVector;
+}
+
+void Node::insertedIntoDocument()
+{
+ if (!eventListeners().isEmpty())
+ document()->unregisterDisconnectedNodeWithEventListeners(this);
+
+ setInDocument(true);
+}
+
+void Node::removedFromDocument()
+{
+ if (!eventListeners().isEmpty())
+ document()->registerDisconnectedNodeWithEventListeners(this);
+
+ setInDocument(false);
+}
+
+void Node::willMoveToNewOwnerDocument()
+{
+ if (!eventListeners().isEmpty())
+ document()->unregisterDisconnectedNodeWithEventListeners(this);
+}
+
+void Node::didMoveToNewOwnerDocument()
+{
+ if (!eventListeners().isEmpty())
+ document()->registerDisconnectedNodeWithEventListeners(this);
+}
+
+static inline void updateSVGElementInstancesAfterEventListenerChange(Node* 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 Node::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
+{
+ Document* document = this->document();
+ if (!document->attached())
+ return;
+
+ document->addListenerTypeIfNeeded(eventType);
+
+ RegisteredEventListenerVector& listeners = ensureRareData()->ensureListeners();
+
+ // 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 (listeners.isEmpty() && !inDocument())
+ document->registerDisconnectedNodeWithEventListeners(this);
+
+ listeners.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)
+ document->addTouchEventListener(this);
+#endif
+}
+
+void Node::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
+{
+ if (!hasRareData())
+ return;
+
+ RegisteredEventListenerVector* listeners = rareData()->listeners();
+ if (!listeners)
+ return;
+
+ size_t size = listeners->size();
+ for (size_t i = 0; i < size; ++i) {
+ RegisteredEventListener& r = *listeners->at(i);
+ if (r.eventType() == eventType && r.listener() == listener && r.useCapture() == useCapture) {
+ r.setRemoved(true);
+ listeners->remove(i);
+
+ // removed last
+ if (listeners->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 Node::removeAllEventListenersSlowCase()
+{
+ ASSERT(hasRareData());
+
+ RegisteredEventListenerVector* listeners = rareData()->listeners();
+ if (!listeners)
+ return;
+
+#if ENABLE(TOUCH_EVENTS) // Android
+ document()->removeTouchEventListener(this);
+#endif
+
+ size_t size = listeners->size();
+ for (size_t i = 0; i < size; ++i)
+ listeners->at(i)->setRemoved(true);
+ listeners->clear();
+}
+
+void Node::handleLocalEvents(Event* event, bool useCapture)
+{
+ if (disabled() && event->isMouseEvent())
+ return;
+
+ RegisteredEventListenerVector listenersCopy = eventListeners();
+ size_t size = listenersCopy.size();
+ for (size_t i = 0; i < size; ++i) {
+ const RegisteredEventListener& r = *listenersCopy[i];
+ if (r.eventType() == event->type() && r.useCapture() == useCapture && !r.removed())
+ r.listener()->handleEvent(event, false);
+ }
+}
+
+#if ENABLE(SVG)
+static inline SVGElementInstance* eventTargetAsSVGElementInstance(Node* 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(Node* referenceNode)
+{
+ ASSERT(referenceNode);
+
+#if ENABLE(SVG)
+ if (SVGElementInstance* instance = eventTargetAsSVGElementInstance(referenceNode)) {
+ ASSERT(instance->shadowTreeElement() == referenceNode);
+ return instance;
+ }
+#endif
+
+ return referenceNode;
+}
+
+bool Node::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());
+}
+
+bool Node::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<Node> 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) {
+ Node* 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 Node::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 Node::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 Node::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 Node::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 Node::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 Node::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 Node::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 Node::dispatchSimulatedClick(PassRefPtr<Event> event, bool sendMouseEvents, bool showPressedLook)
+{
+ if (!gNodesDispatchingSimulatedClicks)
+ gNodesDispatchingSimulatedClicks = new HashSet<Node*>;
+ 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 Node::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<Node> relatedTarget = relatedTargetArg;
+
+ int adjustedPageX = pageX;
+ int adjustedPageY = pageY;
+ if (Frame* frame = document()->frame()) {
+ float pageZoom = frame->pageZoomFactor();
+ if (pageZoom != 1.0f) {
+ // Adjust our pageX and pageY to account for the page zoom.
+ adjustedPageX = lroundf(pageX / pageZoom);
+ adjustedPageY = lroundf(pageY / pageZoom);
+ }
+ }
+
+ RefPtr<MouseEvent> mouseEvent = MouseEvent::create(eventType,
+ true, cancelable, document()->defaultView(),
+ detail, screenX, screenY, adjustedPageX, adjustedPageY,
+ ctrlKey, altKey, shiftKey, metaKey, button,
+ relatedTarget, 0, isSimulated);
+ mouseEvent->setUnderlyingEvent(underlyingEvent.get());
+ mouseEvent->setAbsoluteLocation(IntPoint(pageX, pageY));
+
+ 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 Node::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());
+
+ int adjustedPageX = pos.x();
+ int adjustedPageY = pos.y();
+ if (Frame* frame = document()->frame()) {
+ float pageZoom = frame->pageZoomFactor();
+ if (pageZoom != 1.0f) {
+ // Adjust our pageX and pageY to account for the page zoom.
+ adjustedPageX = lroundf(pos.x() / pageZoom);
+ adjustedPageY = lroundf(pos.y() / pageZoom);
+ }
+ }
+
+ RefPtr<WheelEvent> we = WheelEvent::create(e.wheelTicksX(), e.wheelTicksY(),
+ document()->defaultView(), e.globalX(), e.globalY(), adjustedPageX, adjustedPageY,
+ e.ctrlKey(), e.altKey(), e.shiftKey(), e.metaKey());
+
+ we->setAbsoluteLocation(IntPoint(pos.x(), pos.y()));
+
+ ExceptionCode ec = 0;
+ if (!dispatchEvent(we.release(), ec))
+ e.accept();
+}
+
+bool Node::dispatchWebKitAnimationEvent(const AtomicString& eventType, const String& animationName, double elapsedTime)
+{
+ ASSERT(!eventDispatchForbidden());
+
+ ExceptionCode ec = 0;
+ return dispatchEvent(WebKitAnimationEvent::create(eventType, animationName, elapsedTime), ec);
+}
+
+bool Node::dispatchWebKitTransitionEvent(const AtomicString& eventType, const String& propertyName, double elapsedTime)
+{
+ ASSERT(!eventDispatchForbidden());
+
+ ExceptionCode ec = 0;
+ return dispatchEvent(WebKitTransitionEvent::create(eventType, propertyName, elapsedTime), ec);
+}
+
+void Node::dispatchFocusEvent()
+{
+ dispatchEventForType(eventNames().focusEvent, false, false);
+}
+
+void Node::dispatchBlurEvent()
+{
+ dispatchEventForType(eventNames().blurEvent, false, false);
+}
+
+bool Node::dispatchEventForType(const AtomicString& eventType, bool canBubbleArg, bool cancelableArg)
+{
+ ASSERT(!eventDispatchForbidden());
+ ExceptionCode ec = 0;
+ return dispatchEvent(Event::create(eventType, canBubbleArg, cancelableArg), ec);
+}
+
+bool Node::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 Node::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 Node::removeInlineEventListenerForType(const AtomicString& eventType)
+{
+ if (!hasRareData())
+ return;
+
+ RegisteredEventListenerVector* listeners = rareData()->listeners();
+ if (!listeners)
+ return;
+
+ size_t size = listeners->size();
+ for (size_t i = 0; i < size; ++i) {
+ RegisteredEventListener& r = *listeners->at(i);
+ if (r.eventType() != eventType || !r.listener()->isInline())
+ continue;
+
+ r.setRemoved(true);
+ listeners->remove(i);
+
+ // removed last
+ if (listeners->isEmpty() && !inDocument())
+ document()->unregisterDisconnectedNodeWithEventListeners(this);
+
+ updateSVGElementInstancesAfterEventListenerChange(this);
+ return;
+ }
+}
+
+void Node::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 Node::setInlineEventListenerForTypeAndAttribute(const AtomicString& eventType, Attribute* attr)
+{
+ setInlineEventListenerForType(eventType, document()->createEventListener(attr->localName().string(), attr->value(), this));
+}
+
+EventListener* Node::inlineEventListenerForType(const AtomicString& eventType) const
+{
+ const RegisteredEventListenerVector& listeners = eventListeners();
+ size_t size = listeners.size();
+ for (size_t i = 0; i < size; ++i) {
+ const RegisteredEventListener& r = *listeners[i];
+ if (r.eventType() == eventType && r.listener()->isInline())
+ return r.listener();
+ }
+ return 0;
+}
+
+bool Node::disabled() const
+{
+ return false;
+}
+
+void Node::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* Node::onabort() const
+{
+ return inlineEventListenerForType(eventNames().abortEvent);
+}
+
+void Node::setOnabort(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().abortEvent, eventListener);
+}
+
+EventListener* Node::onblur() const
+{
+ return inlineEventListenerForType(eventNames().blurEvent);
+}
+
+void Node::setOnblur(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().blurEvent, eventListener);
+}
+
+EventListener* Node::onchange() const
+{
+ return inlineEventListenerForType(eventNames().changeEvent);
+}
+
+void Node::setOnchange(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().changeEvent, eventListener);
+}
+
+EventListener* Node::onclick() const
+{
+ return inlineEventListenerForType(eventNames().clickEvent);
+}
+
+void Node::setOnclick(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().clickEvent, eventListener);
+}
+
+EventListener* Node::oncontextmenu() const
+{
+ return inlineEventListenerForType(eventNames().contextmenuEvent);
+}
+
+void Node::setOncontextmenu(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().contextmenuEvent, eventListener);
+}
+
+EventListener* Node::ondblclick() const
+{
+ return inlineEventListenerForType(eventNames().dblclickEvent);
+}
+
+void Node::setOndblclick(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().dblclickEvent, eventListener);
+}
+
+EventListener* Node::onerror() const
+{
+ return inlineEventListenerForType(eventNames().errorEvent);
+}
+
+void Node::setOnerror(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().errorEvent, eventListener);
+}
+
+EventListener* Node::onfocus() const
+{
+ return inlineEventListenerForType(eventNames().focusEvent);
+}
+
+void Node::setOnfocus(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().focusEvent, eventListener);
+}
+
+EventListener* Node::oninput() const
+{
+ return inlineEventListenerForType(eventNames().inputEvent);
+}
+
+void Node::setOninput(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().inputEvent, eventListener);
+}
+
+EventListener* Node::onkeydown() const
+{
+ return inlineEventListenerForType(eventNames().keydownEvent);
+}
+
+void Node::setOnkeydown(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().keydownEvent, eventListener);
+}
+
+EventListener* Node::onkeypress() const
+{
+ return inlineEventListenerForType(eventNames().keypressEvent);
+}
+
+void Node::setOnkeypress(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().keypressEvent, eventListener);
+}
+
+EventListener* Node::onkeyup() const
+{
+ return inlineEventListenerForType(eventNames().keyupEvent);
+}
+
+void Node::setOnkeyup(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().keyupEvent, eventListener);
+}
+
+EventListener* Node::onload() const
+{
+ return inlineEventListenerForType(eventNames().loadEvent);
+}
+
+void Node::setOnload(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().loadEvent, eventListener);
+}
+
+EventListener* Node::onmousedown() const
+{
+ return inlineEventListenerForType(eventNames().mousedownEvent);
+}
+
+void Node::setOnmousedown(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().mousedownEvent, eventListener);
+}
+
+EventListener* Node::onmousemove() const
+{
+ return inlineEventListenerForType(eventNames().mousemoveEvent);
+}
+
+void Node::setOnmousemove(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().mousemoveEvent, eventListener);
+}
+
+EventListener* Node::onmouseout() const
+{
+ return inlineEventListenerForType(eventNames().mouseoutEvent);
+}
+
+void Node::setOnmouseout(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().mouseoutEvent, eventListener);
+}
+
+EventListener* Node::onmouseover() const
+{
+ return inlineEventListenerForType(eventNames().mouseoverEvent);
+}
+
+void Node::setOnmouseover(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().mouseoverEvent, eventListener);
+}
+
+EventListener* Node::onmouseup() const
+{
+ return inlineEventListenerForType(eventNames().mouseupEvent);
+}
+
+void Node::setOnmouseup(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().mouseupEvent, eventListener);
+}
+
+EventListener* Node::onmousewheel() const
+{
+ return inlineEventListenerForType(eventNames().mousewheelEvent);
+}
+
+void Node::setOnmousewheel(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().mousewheelEvent, eventListener);
+}
+
+EventListener* Node::onbeforecut() const
+{
+ return inlineEventListenerForType(eventNames().beforecutEvent);
+}
+
+void Node::setOnbeforecut(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().beforecutEvent, eventListener);
+}
+
+EventListener* Node::oncut() const
+{
+ return inlineEventListenerForType(eventNames().cutEvent);
+}
+
+void Node::setOncut(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().cutEvent, eventListener);
+}
+
+EventListener* Node::onbeforecopy() const
+{
+ return inlineEventListenerForType(eventNames().beforecopyEvent);
+}
+
+void Node::setOnbeforecopy(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().beforecopyEvent, eventListener);
+}
+
+EventListener* Node::oncopy() const
+{
+ return inlineEventListenerForType(eventNames().copyEvent);
+}
+
+void Node::setOncopy(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().copyEvent, eventListener);
+}
+
+EventListener* Node::onbeforepaste() const
+{
+ return inlineEventListenerForType(eventNames().beforepasteEvent);
+}
+
+void Node::setOnbeforepaste(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().beforepasteEvent, eventListener);
+}
+
+EventListener* Node::onpaste() const
+{
+ return inlineEventListenerForType(eventNames().pasteEvent);
+}
+
+void Node::setOnpaste(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().pasteEvent, eventListener);
+}
+
+EventListener* Node::ondragenter() const
+{
+ return inlineEventListenerForType(eventNames().dragenterEvent);
+}
+
+void Node::setOndragenter(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().dragenterEvent, eventListener);
+}
+
+EventListener* Node::ondragover() const
+{
+ return inlineEventListenerForType(eventNames().dragoverEvent);
+}
+
+void Node::setOndragover(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().dragoverEvent, eventListener);
+}
+
+EventListener* Node::ondragleave() const
+{
+ return inlineEventListenerForType(eventNames().dragleaveEvent);
+}
+
+void Node::setOndragleave(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().dragleaveEvent, eventListener);
+}
+
+EventListener* Node::ondrop() const
+{
+ return inlineEventListenerForType(eventNames().dropEvent);
+}
+
+void Node::setOndrop(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().dropEvent, eventListener);
+}
+
+EventListener* Node::ondragstart() const
+{
+ return inlineEventListenerForType(eventNames().dragstartEvent);
+}
+
+void Node::setOndragstart(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().dragstartEvent, eventListener);
+}
+
+EventListener* Node::ondrag() const
+{
+ return inlineEventListenerForType(eventNames().dragEvent);
+}
+
+void Node::setOndrag(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().dragEvent, eventListener);
+}
+
+EventListener* Node::ondragend() const
+{
+ return inlineEventListenerForType(eventNames().dragendEvent);
+}
+
+void Node::setOndragend(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().dragendEvent, eventListener);
+}
+
+EventListener* Node::onreset() const
+{
+ return inlineEventListenerForType(eventNames().resetEvent);
+}
+
+void Node::setOnreset(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().resetEvent, eventListener);
+}
+
+EventListener* Node::onresize() const
+{
+ return inlineEventListenerForType(eventNames().resizeEvent);
+}
+
+void Node::setOnresize(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().resizeEvent, eventListener);
+}
+
+EventListener* Node::onscroll() const
+{
+ return inlineEventListenerForType(eventNames().scrollEvent);
+}
+
+void Node::setOnscroll(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().scrollEvent, eventListener);
+}
+
+EventListener* Node::onsearch() const
+{
+ return inlineEventListenerForType(eventNames().searchEvent);
+}
+
+void Node::setOnsearch(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().searchEvent, eventListener);
+}
+
+EventListener* Node::onselect() const
+{
+ return inlineEventListenerForType(eventNames().selectEvent);
+}
+
+void Node::setOnselect(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().selectEvent, eventListener);
+}
+
+EventListener* Node::onselectstart() const
+{
+ return inlineEventListenerForType(eventNames().selectstartEvent);
+}
+
+void Node::setOnselectstart(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().selectstartEvent, eventListener);
+}
+
+EventListener* Node::onsubmit() const
+{
+ return inlineEventListenerForType(eventNames().submitEvent);
+}
+
+void Node::setOnsubmit(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().submitEvent, eventListener);
+}
+
+EventListener* Node::onunload() const
+{
+ return inlineEventListenerForType(eventNames().unloadEvent);
+}
+
+void Node::setOnunload(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().unloadEvent, eventListener);
+}
+
+#if ENABLE(TOUCH_EVENTS) // Android
+EventListener* Node::ontouchstart() const
+{
+ return inlineEventListenerForType(eventNames().touchstartEvent);
+}
+
+void Node::setOntouchstart(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().touchstartEvent, eventListener);
+}
+
+EventListener* Node::ontouchend() const
+{
+ return inlineEventListenerForType(eventNames().touchendEvent);
+}
+
+void Node::setOntouchend(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().touchendEvent, eventListener);
+}
+
+EventListener* Node::ontouchmove() const
+{
+ return inlineEventListenerForType(eventNames().touchmoveEvent);
+}
+
+void Node::setOntouchmove(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().touchmoveEvent, eventListener);
+}
+
+EventListener* Node::ontouchcancel() const
+{
+ return inlineEventListenerForType(eventNames().touchcancelEvent);
+}
+
+void Node::setOntouchcancel(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().touchcancelEvent, eventListener);
+}
+#endif // ENABLE(TOUCH_EVENT)
+
} // namespace WebCore
#ifndef NDEBUG