diff options
author | Jocelyn Turcotte <jocelyn.turcotte@nokia.com> | 2010-04-06 12:36:47 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@nokia.com> | 2010-04-06 12:36:47 +0200 |
commit | bb35b65bbfba82e0dd0ac306d3dab54436cdaff6 (patch) | |
tree | 8174cb262a960ff7b2e4aa8f1aaf154db71d2636 /src/3rdparty/webkit/WebCore/dom/Node.cpp | |
parent | 4b27d0d887269583a0f76e922948f8c25e96ab88 (diff) | |
download | qt4-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.cpp | 355 |
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); } } |