summaryrefslogtreecommitdiff
path: root/src/3rdparty/webkit/WebCore/dom/Node.cpp
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@nokia.com>2010-04-06 12:36:47 +0200
committerJocelyn Turcotte <jocelyn.turcotte@nokia.com>2010-04-06 12:36:47 +0200
commitbb35b65bbfba82e0dd0ac306d3dab54436cdaff6 (patch)
tree8174cb262a960ff7b2e4aa8f1aaf154db71d2636 /src/3rdparty/webkit/WebCore/dom/Node.cpp
parent4b27d0d887269583a0f76e922948f8c25e96ab88 (diff)
downloadqt4-tools-bb35b65bbfba82e0dd0ac306d3dab54436cdaff6.tar.gz
Update src/3rdparty/webkit from trunk.
Imported from 839d8709327f925aacb3b6362c06152594def97e in branch qtwebkit-2.0 of repository git://gitorious.org/+qtwebkit-developers/webkit/qtwebkit.git Rubber-stamped-by: Simon Hausmann
Diffstat (limited to 'src/3rdparty/webkit/WebCore/dom/Node.cpp')
-rw-r--r--src/3rdparty/webkit/WebCore/dom/Node.cpp355
1 files changed, 268 insertions, 87 deletions
diff --git a/src/3rdparty/webkit/WebCore/dom/Node.cpp b/src/3rdparty/webkit/WebCore/dom/Node.cpp
index 612bf18ef3..95f5dce453 100644
--- a/src/3rdparty/webkit/WebCore/dom/Node.cpp
+++ b/src/3rdparty/webkit/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, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
*
@@ -37,6 +37,7 @@
#include "CString.h"
#include "ChildNodeList.h"
#include "ClassNodeList.h"
+#include "ContextMenuController.h"
#include "DOMImplementation.h"
#include "Document.h"
#include "DynamicNodeList.h"
@@ -53,6 +54,7 @@
#include "InspectorTimelineAgent.h"
#include "KeyboardEvent.h"
#include "Logging.h"
+#include "MappedAttribute.h"
#include "MouseEvent.h"
#include "MutationEvent.h"
#include "NameNodeList.h"
@@ -143,7 +145,7 @@ void Node::dumpStatistics()
size_t attrMaps = 0;
size_t mappedAttrMaps = 0;
- for (HashSet<Node*>::const_iterator it = liveNodeSet.begin(); it != liveNodeSet.end(); ++it) {
+ for (HashSet<Node*>::iterator it = liveNodeSet.begin(); it != liveNodeSet.end(); ++it) {
Node* node = *it;
if (node->hasRareData())
@@ -249,7 +251,7 @@ void Node::dumpStatistics()
printf(" Number of XPathNS nodes: %zu\n", xpathNSNodes);
printf("Element tag name distibution:\n");
- for (HashMap<String, size_t>::const_iterator it = perTagCount.begin(); it != perTagCount.end(); ++it)
+ for (HashMap<String, size_t>::iterator it = perTagCount.begin(); it != perTagCount.end(); ++it)
printf(" Number of <%s> tags: %zu\n", it->first.utf8().data(), it->second);
printf("Attribute Maps:\n");
@@ -311,25 +313,20 @@ Node::StyleChange Node::diff(const RenderStyle* s1, const 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(BEFORE)) {
- RenderStyle* ps2 = s2->getCachedPseudoStyle(BEFORE);
- if (!ps2)
- ch = NoInherit;
- else {
- RenderStyle* ps1 = s1->getCachedPseudoStyle(BEFORE);
- ch = ps1 && *ps1 == *ps2 ? NoChange : NoInherit;
- }
- }
- if (ch == NoChange && s1->hasPseudoStyle(AFTER)) {
- RenderStyle* ps2 = s2->getCachedPseudoStyle(AFTER);
- if (!ps2)
- ch = NoInherit;
- else {
- RenderStyle* ps1 = s1->getCachedPseudoStyle(AFTER);
- ch = ps2 && *ps1 == *ps2 ? NoChange : NoInherit;
+ if (ch == NoChange && s1->hasAnyPublicPseudoStyles()) {
+ for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; ch == NoChange && pseudoId < FIRST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
+ if (s1->hasPseudoStyle(pseudoId)) {
+ RenderStyle* ps2 = s2->getCachedPseudoStyle(pseudoId);
+ if (!ps2)
+ ch = NoInherit;
+ else {
+ RenderStyle* ps1 = s1->getCachedPseudoStyle(pseudoId);
+ ch = ps1 && *ps1 == *ps2 ? NoChange : NoInherit;
+ }
+ }
}
}
-
+
return ch;
}
@@ -410,7 +407,6 @@ Node::Node(Document* document, ConstructionType type)
, m_hovered(false)
, m_inActiveChain(false)
, m_inDetach(false)
- , m_inSubtreeMark(false)
, m_hasRareData(false)
, m_isElement(isElement(type))
, m_isContainer(isContainer(type))
@@ -421,6 +417,7 @@ Node::Node(Document* document, ConstructionType type)
#if ENABLE(SVG)
, m_areSVGAttributesValid(true)
, m_synchronizingSVGAttributes(false)
+ , m_hasRareSVGData(false)
#endif
{
if (m_document)
@@ -519,6 +516,12 @@ void Node::setDocument(Document* document)
updateDOMNodeDocument(this, m_document, document);
#endif
+ if (hasRareData() && rareData()->nodeLists()) {
+ if (m_document)
+ m_document->removeNodeListCache();
+ document->addNodeListCache();
+ }
+
if (m_document)
m_document->selfOnlyDeref();
@@ -674,7 +677,7 @@ void Node::normalize()
// Merge text nodes.
while (Node* nextSibling = node->nextSibling()) {
- if (!nextSibling->isTextNode())
+ if (nextSibling->nodeType() != TEXT_NODE)
break;
RefPtr<Text> nextText = static_cast<Text*>(nextSibling);
@@ -842,7 +845,7 @@ bool Node::isFocusable() const
ASSERT(!renderer()->needsLayout());
else
// If the node is in a display:none tree it might say it needs style recalc but
- // the whole document is atually up to date.
+ // the whole document is actually up to date.
ASSERT(!document()->childNeedsStyleRecalc());
// FIXME: Even if we are not visible, we might have a child that is visible.
@@ -910,7 +913,10 @@ void Node::notifyLocalNodeListsAttributeChanged()
if (!data->nodeLists())
return;
- data->nodeLists()->invalidateCachesThatDependOnAttributes();
+ if (!isAttributeNode())
+ data->nodeLists()->invalidateCachesThatDependOnAttributes();
+ else
+ data->nodeLists()->invalidateCaches();
if (data->nodeLists()->isEmpty()) {
data->clearNodeLists();
@@ -1033,34 +1039,27 @@ Node* Node::traversePreviousSiblingPostOrder(const Node* stayWithin) const
return 0;
}
-void Node::checkSetPrefix(const AtomicString&, ExceptionCode& ec)
+void Node::checkSetPrefix(const AtomicString& prefix, ExceptionCode& ec)
{
// Perform error checking as required by spec for setting Node.prefix. Used by
// Element::setPrefix() and Attr::setPrefix()
// FIXME: Implement support for INVALID_CHARACTER_ERR: Raised if the specified prefix contains an illegal character.
- // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
if (isReadOnlyNode()) {
ec = NO_MODIFICATION_ALLOWED_ERR;
return;
}
- // FIXME: Implement NAMESPACE_ERR: - Raised if the specified prefix is malformed
- // We have to comment this out, since it's used for attributes and tag names, and we've only
- // switched one over.
- /*
- // - if the namespaceURI of this node is null,
- // - if the specified prefix is "xml" and the namespaceURI of this node is different from
- // "http://www.w3.org/XML/1998/namespace",
- // - if this node is an attribute and the specified prefix is "xmlns" and
- // the namespaceURI of this node is different from "http://www.w3.org/2000/xmlns/",
- // - or if this node is an attribute and the qualifiedName of this node is "xmlns" [Namespaces].
- if ((namespacePart(id()) == noNamespace && id() > ID_LAST_TAG) ||
- (_prefix == "xml" && String(document()->namespaceURI(id())) != "http://www.w3.org/XML/1998/namespace")) {
+ // FIXME: Raise NAMESPACE_ERR if prefix is malformed per the Namespaces in XML specification.
+
+ const AtomicString& nodeNamespaceURI = namespaceURI();
+ if ((nodeNamespaceURI.isEmpty() && !prefix.isEmpty())
+ || (prefix == xmlAtom && nodeNamespaceURI != XMLNames::xmlNamespaceURI)) {
ec = NAMESPACE_ERR;
return;
- }*/
+ }
+ // Attribute-specific checks are in Attr::setPrefix().
}
bool Node::canReplaceChild(Node* newChild, Node*)
@@ -1464,7 +1463,7 @@ bool Node::canStartSelection() const
Node* Node::shadowAncestorNode()
{
#if ENABLE(SVG)
- // SVG elements living in a shadow tree only occour when <use> created them.
+ // SVG elements living in a shadow tree only occur when <use> created them.
// For these cases we do NOT want to return the shadowParentNode() here
// but the actual shadow tree element - as main difference to the HTML forms
// shadow tree concept. (This function _could_ be made virtual - opinions?)
@@ -1653,7 +1652,6 @@ PassRefPtr<Element> Node::querySelector(const String& selectors, ExceptionCode&
// FIXME: we could also optimize for the the [id="foo"] case
if (strictParsing && inDocument() && querySelectorList.hasOneSelector() && querySelectorList.first()->m_match == CSSSelector::Id) {
- ASSERT(querySelectorList.first()->attribute() == idAttr);
Element* element = document()->getElementById(querySelectorList.first()->m_value);
if (element && (isDocumentNode() || element->isDescendantOf(this)) && selectorChecker.checkSelector(querySelectorList.first(), element))
return element;
@@ -1763,25 +1761,24 @@ bool Node::isEqualNode(Node *other) const
return true;
}
-bool Node::isDefaultNamespace(const AtomicString &namespaceURI) const
+bool Node::isDefaultNamespace(const AtomicString& namespaceURIMaybeEmpty) const
{
- // Implemented according to
- // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html#isDefaultNamespaceAlgo
-
+ const AtomicString& namespaceURI = namespaceURIMaybeEmpty.isEmpty() ? nullAtom : namespaceURIMaybeEmpty;
+
switch (nodeType()) {
case ELEMENT_NODE: {
- const Element *elem = static_cast<const Element *>(this);
+ const Element* elem = static_cast<const Element*>(this);
if (elem->prefix().isNull())
return elem->namespaceURI() == namespaceURI;
if (elem->hasAttributes()) {
- NamedNodeMap *attrs = elem->attributes();
+ NamedNodeMap* attrs = elem->attributes();
for (unsigned i = 0; i < attrs->length(); i++) {
- Attribute *attr = attrs->attributeItem(i);
+ Attribute* attr = attrs->attributeItem(i);
- if (attr->localName() == "xmlns")
+ if (attr->localName() == xmlnsAtom)
return attr->value() == namespaceURI;
}
}
@@ -1801,7 +1798,7 @@ bool Node::isDefaultNamespace(const AtomicString &namespaceURI) const
case DOCUMENT_FRAGMENT_NODE:
return false;
case ATTRIBUTE_NODE: {
- const Attr *attr = static_cast<const Attr *>(this);
+ const Attr* attr = static_cast<const Attr*>(this);
if (attr->ownerElement())
return attr->ownerElement()->isDefaultNamespace(namespaceURI);
return false;
@@ -1867,12 +1864,12 @@ String Node::lookupNamespaceURI(const String &prefix) const
for (unsigned i = 0; i < attrs->length(); i++) {
Attribute *attr = attrs->attributeItem(i);
- if (attr->prefix() == "xmlns" && attr->localName() == prefix) {
+ if (attr->prefix() == xmlnsAtom && attr->localName() == prefix) {
if (!attr->value().isEmpty())
return attr->value();
return String();
- } else if (attr->localName() == "xmlns" && prefix.isNull()) {
+ } else if (attr->localName() == xmlnsAtom && prefix.isNull()) {
if (!attr->value().isEmpty())
return attr->value();
@@ -1922,7 +1919,7 @@ String Node::lookupNamespacePrefix(const AtomicString &_namespaceURI, const Elem
for (unsigned i = 0; i < attrs->length(); i++) {
Attribute *attr = attrs->attributeItem(i);
- if (attr->prefix() == "xmlns" &&
+ if (attr->prefix() == xmlnsAtom &&
attr->value() == _namespaceURI &&
originalElement->lookupNamespaceURI(attr->localName()) == _namespaceURI)
return attr->localName();
@@ -2289,6 +2286,19 @@ ContainerNode* Node::eventParentNode()
return static_cast<ContainerNode*>(parent);
}
+Node* Node::enclosingLinkEventParentOrSelf()
+{
+ for (Node* node = this; node; node = node->eventParentNode()) {
+ // For imagemaps, the enclosing link node is the associated area element not the image itself.
+ // So we don't let images be the enclosingLinkNode, even though isLink sometimes returns true
+ // for them.
+ if (node->isLink() && !node->hasTagName(imgTag))
+ return node;
+ }
+
+ return 0;
+}
+
// --------
ScriptExecutionContext* Node::scriptExecutionContext() const
@@ -2318,49 +2328,159 @@ void Node::didMoveToNewOwnerDocument()
setDidMoveToNewOwnerDocumentWasCalled(true);
}
-static inline void updateSVGElementInstancesAfterEventListenerChange(Node* referenceNode)
+#if ENABLE(SVG)
+static inline HashSet<SVGElementInstance*> instancesForSVGElement(Node* node)
+{
+ HashSet<SVGElementInstance*> instances;
+
+ ASSERT(node);
+ if (!node->isSVGElement() || node->shadowTreeRootNode())
+ return HashSet<SVGElementInstance*>();
+
+ SVGElement* element = static_cast<SVGElement*>(node);
+ if (!element->isStyled())
+ return HashSet<SVGElementInstance*>();
+
+ SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(element);
+ ASSERT(!styledElement->instanceUpdatesBlocked());
+
+ return styledElement->instancesForElement();
+}
+#endif
+
+static inline bool tryAddEventListener(Node* targetNode, const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
+{
+ if (!targetNode->EventTarget::addEventListener(eventType, listener, useCapture))
+ return false;
+
+ if (Document* document = targetNode->document())
+ document->addListenerTypeIfNeeded(eventType);
+
+ return true;
+}
+
+bool Node::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
{
#if !ENABLE(SVG)
- UNUSED_PARAM(referenceNode);
+ return tryAddEventListener(this, eventType, listener, useCapture);
#else
- ASSERT(referenceNode);
- if (!referenceNode->isSVGElement())
- return;
+ if (!isSVGElement())
+ return tryAddEventListener(this, eventType, listener, useCapture);
- // Elements living inside a <use> shadow tree, never cause any updates!
- if (referenceNode->shadowTreeRootNode())
- return;
+ HashSet<SVGElementInstance*> instances = instancesForSVGElement(this);
+ if (instances.isEmpty())
+ return tryAddEventListener(this, eventType, listener, useCapture);
- // 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;
+ RefPtr<EventListener> listenerForRegularTree = listener;
+ RefPtr<EventListener> listenerForShadowTree = listenerForRegularTree;
- SVGElementInstance::invalidateAllInstancesOfElement(static_cast<SVGElement*>(node));
- break;
+ // Add event listener to regular DOM element
+ if (!tryAddEventListener(this, eventType, listenerForRegularTree.release(), useCapture))
+ return false;
+
+ // Add event listener to all shadow tree DOM element instances
+ const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
+ for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
+ ASSERT((*it)->shadowTreeElement());
+ ASSERT((*it)->correspondingElement() == this);
+
+ RefPtr<EventListener> listenerForCurrentShadowTreeElement = listenerForShadowTree;
+ bool result = tryAddEventListener((*it)->shadowTreeElement(), eventType, listenerForCurrentShadowTreeElement.release(), useCapture);
+ ASSERT_UNUSED(result, result);
}
+
+ return true;
#endif
}
-bool Node::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
+static inline bool tryRemoveEventListener(Node* targetNode, const AtomicString& eventType, EventListener* listener, bool useCapture)
{
- if (!EventTarget::addEventListener(eventType, listener, useCapture))
+ if (!targetNode->EventTarget::removeEventListener(eventType, listener, useCapture))
return false;
- if (Document* document = this->document())
- document->addListenerTypeIfNeeded(eventType);
- updateSVGElementInstancesAfterEventListenerChange(this);
+ // FIXME: Notify Document that the listener has vanished. We need to keep track of a number of
+ // listeners for each type, not just a bool - see https://bugs.webkit.org/show_bug.cgi?id=33861
+
return true;
}
bool Node::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
{
- if (!EventTarget::removeEventListener(eventType, listener, useCapture))
+#if !ENABLE(SVG)
+ return tryRemoveEventListener(this, eventType, listener, useCapture);
+#else
+ if (!isSVGElement())
+ return tryRemoveEventListener(this, eventType, listener, useCapture);
+
+ HashSet<SVGElementInstance*> instances = instancesForSVGElement(this);
+ if (instances.isEmpty())
+ return tryRemoveEventListener(this, eventType, listener, useCapture);
+
+ // EventTarget::removeEventListener creates a PassRefPtr around the given EventListener
+ // object when creating a temporary RegisteredEventListener object used to look up the
+ // event listener in a cache. If we want to be able to call removeEventListener() multiple
+ // times on different nodes, we have to delay its immediate destruction, which would happen
+ // after the first call below.
+ RefPtr<EventListener> protector(listener);
+
+ // Remove event listener from regular DOM element
+ if (!tryRemoveEventListener(this, eventType, listener, useCapture))
return false;
- updateSVGElementInstancesAfterEventListenerChange(this);
+ // Remove event listener from all shadow tree DOM element instances
+ const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
+ for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
+ ASSERT((*it)->correspondingElement() == this);
+
+ SVGElement* shadowTreeElement = (*it)->shadowTreeElement();
+ ASSERT(shadowTreeElement);
+
+ if (tryRemoveEventListener(shadowTreeElement, eventType, listener, useCapture))
+ continue;
+
+ // This case can only be hit for event listeners created from markup
+ ASSERT(listener->wasCreatedFromMarkup());
+
+ // If the event listener 'listener' has been created from markup and has been fired before
+ // then JSLazyEventListener::parseCode() has been called and m_jsFunction of that listener
+ // has been created (read: it's not 0 anymore). During shadow tree creation, the event
+ // listener DOM attribute has been cloned, and another event listener has been setup in
+ // the shadow tree. If that event listener has not been used yet, m_jsFunction is still 0,
+ // and tryRemoveEventListener() above will fail. Work around that very seldom problem.
+ EventTargetData* data = shadowTreeElement->eventTargetData();
+ ASSERT(data);
+
+ EventListenerMap::iterator result = data->eventListenerMap.find(eventType);
+ ASSERT(result != data->eventListenerMap.end());
+
+ EventListenerVector* entry = result->second;
+ ASSERT(entry);
+
+ unsigned int index = 0;
+ bool foundListener = false;
+
+ EventListenerVector::iterator end = entry->end();
+ for (EventListenerVector::iterator it = entry->begin(); it != end; ++it) {
+ if (!(*it).listener->wasCreatedFromMarkup()) {
+ ++index;
+ continue;
+ }
+
+ foundListener = true;
+ entry->remove(index);
+ break;
+ }
+
+ ASSERT(foundListener);
+
+ if (entry->isEmpty()) {
+ delete entry;
+ data->eventListenerMap.remove(result);
+ }
+ }
+
return true;
+#endif
}
EventTargetData* Node::eventTargetData()
@@ -2447,6 +2567,23 @@ bool Node::dispatchEvent(PassRefPtr<Event> prpEvent)
return dispatchGenericEvent(event.release());
}
+static bool eventHasListeners(const AtomicString& eventType, DOMWindow* window, Node* node, Vector<RefPtr<ContainerNode> >& ancestors)
+{
+ if (window && window->hasEventListeners(eventType))
+ return true;
+
+ if (node->hasEventListeners(eventType))
+ return true;
+
+ for (size_t i = 0; i < ancestors.size(); i++) {
+ ContainerNode* ancestor = ancestors[i].get();
+ if (ancestor->hasEventListeners(eventType))
+ return true;
+ }
+
+ return false;
+}
+
bool Node::dispatchGenericEvent(PassRefPtr<Event> prpEvent)
{
RefPtr<Event> event(prpEvent);
@@ -2455,12 +2592,6 @@ bool Node::dispatchGenericEvent(PassRefPtr<Event> prpEvent)
ASSERT(event->target());
ASSERT(!event->type().isNull()); // JavaScript code can create an event with an empty name, but not null.
-#if ENABLE(INSPECTOR)
- InspectorTimelineAgent* timelineAgent = document()->inspectorTimelineAgent();
- if (timelineAgent)
- timelineAgent->willDispatchDOMEvent(*event);
-#endif
-
// 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.
@@ -2478,6 +2609,13 @@ bool Node::dispatchGenericEvent(PassRefPtr<Event> prpEvent)
targetForWindowEvents = static_cast<Document*>(topLevelContainer)->domWindow();
}
+#if ENABLE(INSPECTOR)
+ InspectorTimelineAgent* timelineAgent = document()->inspectorTimelineAgent();
+ bool timelineAgentIsActive = timelineAgent && eventHasListeners(event->type(), targetForWindowEvents, this, ancestors);
+ if (timelineAgentIsActive)
+ timelineAgent->willDispatchEvent(*event);
+#endif
+
// 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())
@@ -2559,8 +2697,8 @@ doneDispatching:
doneWithDefault:
#if ENABLE(INSPECTOR)
- if (timelineAgent)
- timelineAgent->didDispatchDOMEvent();
+ if (timelineAgentIsActive && (timelineAgent = document()->inspectorTimelineAgent()))
+ timelineAgent->didDispatchEvent();
#endif
Document::updateStyleForAllDocuments();
@@ -2585,7 +2723,8 @@ void Node::dispatchSubtreeModifiedEvent()
void Node::dispatchUIEvent(const AtomicString& eventType, int detail, PassRefPtr<Event> underlyingEvent)
{
ASSERT(!eventDispatchForbidden());
- ASSERT(eventType == eventNames().DOMFocusInEvent || eventType == eventNames().DOMFocusOutEvent || eventType == eventNames().DOMActivateEvent);
+ ASSERT(eventType == eventNames().focusinEvent || eventType == eventNames().focusoutEvent ||
+ eventType == eventNames().DOMFocusInEvent || eventType == eventNames().DOMFocusOutEvent || eventType == eventNames().DOMActivateEvent);
bool cancelable = eventType == eventNames().DOMActivateEvent;
@@ -2727,7 +2866,7 @@ bool Node::dispatchMouseEvent(const AtomicString& eventType, int button, int det
if (eventType == eventNames().clickEvent && detail == 2) {
RefPtr<Event> doubleClickEvent = MouseEvent::create(eventNames().dblclickEvent,
true, cancelable, document()->defaultView(),
- detail, screenX, screenY, pageX, pageY,
+ detail, screenX, screenY, adjustedPageX, adjustedPageY,
ctrlKey, altKey, shiftKey, metaKey, button,
relatedTarget, 0, isSimulated);
doubleClickEvent->setUnderlyingEvent(underlyingEvent.get());
@@ -2764,14 +2903,27 @@ void Node::dispatchWheelEvent(PlatformWheelEvent& e)
}
}
- RefPtr<WheelEvent> we = WheelEvent::create(e.wheelTicksX(), e.wheelTicksY(),
+ WheelEvent::Granularity granularity;
+ switch (e.granularity()) {
+ case ScrollByPageWheelEvent:
+ granularity = WheelEvent::Page;
+ break;
+ case ScrollByPixelWheelEvent:
+ default:
+ granularity = WheelEvent::Pixel;
+ break;
+ }
+
+ RefPtr<WheelEvent> we = WheelEvent::create(e.wheelTicksX(), e.wheelTicksY(), e.deltaX(), e.deltaY(), granularity,
document()->defaultView(), e.globalX(), e.globalY(), adjustedPageX, adjustedPageY,
e.ctrlKey(), e.altKey(), e.shiftKey(), e.metaKey());
we->setAbsoluteLocation(IntPoint(pos.x(), pos.y()));
- if (!dispatchEvent(we.release()))
+ if (!dispatchEvent(we) || we->defaultHandled())
e.accept();
+
+ we.release();
}
void Node::dispatchFocusEvent()
@@ -2811,6 +2963,35 @@ void Node::defaultEventHandler(Event* event)
if (event->isTextEvent())
if (Frame* frame = document()->frame())
frame->eventHandler()->defaultTextInputEventHandler(static_cast<TextEvent*>(event));
+#if ENABLE(PAN_SCROLLING)
+ } else if (eventType == eventNames().mousedownEvent) {
+ MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
+ if (mouseEvent->button() == MiddleButton) {
+ if (enclosingLinkEventParentOrSelf())
+ return;
+
+ RenderObject* renderer = this->renderer();
+ while (renderer && (!renderer->isBox() || !toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()))
+ renderer = renderer->parent();
+
+ if (renderer) {
+ if (Frame* frame = document()->frame())
+ frame->eventHandler()->startPanScrolling(renderer);
+ }
+ }
+#endif
+ } else if (eventType == eventNames().mousewheelEvent && event->isWheelEvent()) {
+ WheelEvent* wheelEvent = static_cast<WheelEvent*>(event);
+
+ // If we don't have a renderer, send the wheel event to the first node we find with a renderer.
+ // This is needed for <option> and <optgroup> elements so that <select>s get a wheel scroll.
+ Node* startNode = this;
+ while (startNode && !startNode->renderer())
+ startNode = startNode->parent();
+
+ if (startNode && startNode->renderer())
+ if (Frame* frame = document()->frame())
+ frame->eventHandler()->defaultWheelEventHandler(startNode, wheelEvent);
}
}