Changeset 149173 in webkit


Ignore:
Timestamp:
Apr 26, 2013 2:42:11 AM (11 years ago)
Author:
allan.jensen@digia.com
Message:

Mouseenter and mouseleave events not supported
https://bugs.webkit.org/show_bug.cgi?id=18930

Reviewed by David Hyatt.

Source/WebCore:

Implements mouseenter and mouseleave events from W3C DOM Level 3 Events.
These event are already supported by all other major browsers.

To avoid performance regressions the new events are only dispatched when
there are event listeners for them.

Tests: fast/events/mouseenter-mouseleave-capture.html

fast/events/mouseenter-mouseleave.html

  • bindings/scripts/CodeGenerator.pm:
  • dom/Document.cpp:

(WebCore::Document::prepareMouseEvent):
(WebCore::Document::updateHoverActiveState):

  • dom/Document.h:

(Document):

  • dom/Document.idl:
  • dom/Element.h:

(Element):

  • dom/Element.idl:
  • dom/EventListenerMap.cpp:

(WebCore::EventListenerMap::containsCapturing):

  • dom/EventListenerMap.h:

(EventListenerMap):

  • dom/EventNames.h:
  • dom/EventTarget.h:

(EventTarget):
(WebCore::EventTarget::hasCapturingEventListeners):

  • dom/MouseEvent.cpp:

(WebCore::MouseEvent::create):
(WebCore::MouseEvent::toElement):
(WebCore::MouseEvent::fromElement):

  • html/HTMLAttributeNames.in:
  • html/HTMLElement.cpp:

(WebCore::HTMLElement::eventNameForAttributeName):

  • page/DOMWindow.h:

(DOMWindow):

  • page/DOMWindow.idl:
  • svg/SVGElement.cpp:

(WebCore::SVGElement::parseAttribute):

  • svg/SVGElementInstance.h:

(SVGElementInstance):

  • svg/SVGElementInstance.idl:

LayoutTests:

To new tests that mouseenter and mouseleave works in both bubbling and capture phase.

  • fast/events/mouseenter-mouseleave-capture-expected.txt: Added.
  • fast/events/mouseenter-mouseleave-capture.html: Added.
  • fast/events/mouseenter-mouseleave-expected.txt: Added.
  • fast/events/mouseenter-mouseleave.html: Added.
Location:
trunk
Files:
4 added
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r149171 r149173  
     12013-04-26  Allan Sandfeld Jensen  <allan.jensen@digia.com>
     2
     3        Mouseenter and mouseleave events not supported
     4        https://bugs.webkit.org/show_bug.cgi?id=18930
     5
     6        Reviewed by David Hyatt.
     7
     8        To new tests that mouseenter and mouseleave works in both bubbling and capture phase.
     9
     10        * fast/events/mouseenter-mouseleave-capture-expected.txt: Added.
     11        * fast/events/mouseenter-mouseleave-capture.html: Added.
     12        * fast/events/mouseenter-mouseleave-expected.txt: Added.
     13        * fast/events/mouseenter-mouseleave.html: Added.
     14
    1152013-04-26  Christophe Dumez  <ch.dumez@sisa.samsung.com>
    216
  • trunk/Source/WebCore/ChangeLog

    r149170 r149173  
     12013-04-26  Allan Sandfeld Jensen  <allan.jensen@digia.com>
     2
     3        Mouseenter and mouseleave events not supported
     4        https://bugs.webkit.org/show_bug.cgi?id=18930
     5
     6        Reviewed by David Hyatt.
     7
     8        Implements mouseenter and mouseleave events from W3C DOM Level 3 Events.
     9        These event are already supported by all other major browsers.
     10
     11        To avoid performance regressions the new events are only dispatched when
     12        there are event listeners for them.
     13
     14        Tests: fast/events/mouseenter-mouseleave-capture.html
     15               fast/events/mouseenter-mouseleave.html
     16
     17        * bindings/scripts/CodeGenerator.pm:
     18        * dom/Document.cpp:
     19        (WebCore::Document::prepareMouseEvent):
     20        (WebCore::Document::updateHoverActiveState):
     21        * dom/Document.h:
     22        (Document):
     23        * dom/Document.idl:
     24        * dom/Element.h:
     25        (Element):
     26        * dom/Element.idl:
     27        * dom/EventListenerMap.cpp:
     28        (WebCore::EventListenerMap::containsCapturing):
     29        * dom/EventListenerMap.h:
     30        (EventListenerMap):
     31        * dom/EventNames.h:
     32        * dom/EventTarget.h:
     33        (EventTarget):
     34        (WebCore::EventTarget::hasCapturingEventListeners):
     35        * dom/MouseEvent.cpp:
     36        (WebCore::MouseEvent::create):
     37        (WebCore::MouseEvent::toElement):
     38        (WebCore::MouseEvent::fromElement):
     39        * html/HTMLAttributeNames.in:
     40        * html/HTMLElement.cpp:
     41        (WebCore::HTMLElement::eventNameForAttributeName):
     42        * page/DOMWindow.h:
     43        (DOMWindow):
     44        * page/DOMWindow.idl:
     45        * svg/SVGElement.cpp:
     46        (WebCore::SVGElement::parseAttribute):
     47        * svg/SVGElementInstance.h:
     48        (SVGElementInstance):
     49        * svg/SVGElementInstance.idl:
     50
    1512013-04-26  Christophe Dumez  <ch.dumez@sisa.samsung.com>
    252
  • trunk/Source/WebCore/bindings/scripts/CodeGenerator.pm

    r147167 r149173  
    6868my %svgAttributesInHTMLHash = ("class" => 1, "id" => 1, "onabort" => 1, "onclick" => 1,
    6969                               "onerror" => 1, "onload" => 1, "onmousedown" => 1,
     70                               "onmouseenter" => 1, "onmouseleave" => 1,
    7071                               "onmousemove" => 1, "onmouseout" => 1, "onmouseover" => 1,
    7172                               "onmouseup" => 1, "onresize" => 1, "onscroll" => 1,
  • trunk/Source/WebCore/dom/Document.cpp

    r149131 r149173  
    30523052
    30533053    if (!request.readOnly())
    3054         updateHoverActiveState(request, result.innerElement());
     3054        updateHoverActiveState(request, result.innerElement(), &event);
    30553055
    30563056    return MouseEventWithHitTestResults(event, result);
     
    59025902}
    59035903
    5904 void Document::updateHoverActiveState(const HitTestRequest& request, Element* innerElement)
     5904void Document::updateHoverActiveState(const HitTestRequest& request, Element* innerElement, const PlatformMouseEvent* event)
    59055905{
    59065906    ASSERT(!request.readOnly());
     
    59715971    Vector<RefPtr<Node>, 32> nodesToAddToChain;
    59725972
     5973    // mouseenter and mouseleave events are only dispatched if there is a capturing eventhandler on an ancestor
     5974    // or a normal eventhandler on the element itself (they don't bubble).
     5975    // This optimization is necessary since these events can cause O(n²) capturing event-handler checks.
     5976    bool hasCapturingMouseEnterListener = false;
     5977    bool hasCapturingMouseLeaveListener = false;
     5978    if (event && newHoverNode != oldHoverNode.get()) {
     5979        for (Node* curr = newHoverNode; curr; curr = curr->parentOrShadowHostNode()) {
     5980            if (curr->hasCapturingEventListeners(eventNames().mouseenterEvent)) {
     5981                hasCapturingMouseEnterListener = true;
     5982                break;
     5983            }
     5984        }
     5985        for (Node* curr = oldHoverNode.get(); curr; curr = curr->parentOrShadowHostNode()) {
     5986            if (curr->hasCapturingEventListeners(eventNames().mouseleaveEvent)) {
     5987                hasCapturingMouseLeaveListener = true;
     5988                break;
     5989            }
     5990        }
     5991    }
     5992
    59735993    if (oldHoverObj != newHoverObj) {
    59745994        // The old hover path only needs to be cleared up to (and not including) the common ancestor;
     
    59916011
    59926012    size_t removeCount = nodesToRemoveFromChain.size();
    5993     for (size_t i = 0; i < removeCount; ++i)
     6013    for (size_t i = 0; i < removeCount; ++i) {
    59946014        nodesToRemoveFromChain[i]->setHovered(false);
    5995 
     6015        if (event && (hasCapturingMouseLeaveListener || nodesToRemoveFromChain[i]->hasEventListeners(eventNames().mouseleaveEvent)))
     6016            nodesToRemoveFromChain[i]->dispatchMouseEvent(*event, eventNames().mouseleaveEvent, 0, newHoverNode);
     6017    }
     6018
     6019    bool sawCommonAncestor = false;
    59966020    size_t addCount = nodesToAddToChain.size();
    59976021    for (size_t i = 0; i < addCount; ++i) {
    59986022        if (allowActiveChanges)
    59996023            nodesToAddToChain[i]->setActive(true);
    6000         nodesToAddToChain[i]->setHovered(true);
     6024        if (ancestor && nodesToAddToChain[i] == ancestor->node())
     6025            sawCommonAncestor = true;
     6026        if (!sawCommonAncestor) {
     6027            // Elements after the common hover ancestor does not change hover state, but are iterated over because they may change active state.
     6028            nodesToAddToChain[i]->setHovered(true);
     6029            if (event && (hasCapturingMouseEnterListener || nodesToAddToChain[i]->hasEventListeners(eventNames().mouseenterEvent)))
     6030                nodesToAddToChain[i]->dispatchMouseEvent(*event, eventNames().mouseenterEvent, 0, oldHoverNode.get());
     6031        }
    60016032    }
    60026033
  • trunk/Source/WebCore/dom/Document.h

    r149131 r149173  
    266266    DEFINE_ATTRIBUTE_EVENT_LISTENER(keyup);
    267267    DEFINE_ATTRIBUTE_EVENT_LISTENER(mousedown);
     268    DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseenter);
     269    DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseleave);
    268270    DEFINE_ATTRIBUTE_EVENT_LISTENER(mousemove);
    269271    DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseout);
     
    699701    void activeChainNodeDetached(Node*);
    700702
    701     void updateHoverActiveState(const HitTestRequest&, Element*);
     703    void updateHoverActiveState(const HitTestRequest&, Element*, const PlatformMouseEvent* = 0);
    702704
    703705    // Updates for :target (CSS3 selector).
  • trunk/Source/WebCore/dom/Document.idl

    r148098 r149173  
    291291    [NotEnumerable] attribute EventListener onload;
    292292    [NotEnumerable] attribute EventListener onmousedown;
     293    [NotEnumerable] attribute EventListener onmouseenter;
     294    [NotEnumerable] attribute EventListener onmouseleave;
    293295    [NotEnumerable] attribute EventListener onmousemove;
    294296    [NotEnumerable] attribute EventListener onmouseout;
  • trunk/Source/WebCore/dom/Element.h

    r149061 r149173  
    200200    DEFINE_ATTRIBUTE_EVENT_LISTENER(keyup);
    201201    DEFINE_ATTRIBUTE_EVENT_LISTENER(mousedown);
     202    DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseenter);
     203    DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseleave);
    202204    DEFINE_ATTRIBUTE_EVENT_LISTENER(mousemove);
    203205    DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseout);
  • trunk/Source/WebCore/dom/Element.idl

    r147857 r149173  
    183183    [NotEnumerable] attribute EventListener onload;
    184184    [NotEnumerable] attribute EventListener onmousedown;
     185    [NotEnumerable] attribute EventListener onmouseenter;
     186    [NotEnumerable] attribute EventListener onmouseleave;
    185187    [NotEnumerable] attribute EventListener onmousemove;
    186188    [NotEnumerable] attribute EventListener onmouseout;
  • trunk/Source/WebCore/dom/EventListenerMap.cpp

    r128002 r149173  
    7979}
    8080
     81bool EventListenerMap::containsCapturing(const AtomicString& eventType) const
     82{
     83    for (unsigned i = 0; i < m_entries.size(); ++i) {
     84        if (m_entries[i].first == eventType) {
     85            const EventListenerVector* vector = m_entries[i].second.get();
     86            for (unsigned j = 0; j < vector->size(); ++j) {
     87                if (vector->at(j).useCapture)
     88                    return true;
     89            }
     90        }
     91    }
     92    return false;
     93}
     94
    8195void EventListenerMap::clear()
    8296{
  • trunk/Source/WebCore/dom/EventListenerMap.h

    r128002 r149173  
    5151    bool isEmpty() const { return m_entries.isEmpty(); }
    5252    bool contains(const AtomicString& eventType) const;
     53    bool containsCapturing(const AtomicString& eventType) const;
    5354
    5455    void clear();
  • trunk/Source/WebCore/dom/EventNames.h

    r148731 r149173  
    9090    macro(message) \
    9191    macro(mousedown) \
     92    macro(mouseenter) \
     93    macro(mouseleave) \
    9294    macro(mousemove) \
    9395    macro(mouseout) \
  • trunk/Source/WebCore/dom/EventTarget.h

    r148785 r149173  
    127127        bool hasEventListeners();
    128128        bool hasEventListeners(const AtomicString& eventType);
     129        bool hasCapturingEventListeners(const AtomicString& eventType);
    129130        const EventListenerVector& getEventListeners(const AtomicString& eventType);
    130131
     
    207208    }
    208209
     210    inline bool EventTarget::hasCapturingEventListeners(const AtomicString& eventType)
     211    {
     212        EventTargetData* d = eventTargetData();
     213        if (!d)
     214            return false;
     215        return d->eventListenerMap.containsCapturing(eventType);
     216    }
     217
    209218} // namespace WebCore
    210219
  • trunk/Source/WebCore/dom/MouseEvent.cpp

    r147135 r149173  
    5858    ASSERT(event.type() == PlatformEvent::MouseMoved || event.button() != NoButton);
    5959
    60     bool isCancelable = eventType != eventNames().mousemoveEvent;
    61 
    62     return MouseEvent::create(eventType, true, isCancelable, view,
     60    bool isMouseEnterOrLeave = eventType == eventNames().mouseenterEvent || eventType == eventNames().mouseleaveEvent;
     61    bool isCancelable = eventType != eventNames().mousemoveEvent && !isMouseEnterOrLeave;
     62    bool canBubble = !isMouseEnterOrLeave;
     63
     64    return MouseEvent::create(eventType, canBubble, isCancelable, view,
    6365        detail, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
    6466#if ENABLE(POINTER_LOCK)
     
    203205{
    204206    // MSIE extension - "the object toward which the user is moving the mouse pointer"
    205     if (type() == eventNames().mouseoutEvent)
     207    if (type() == eventNames().mouseoutEvent || type() == eventNames().mouseleaveEvent)
    206208        return relatedTarget() ? relatedTarget()->toNode() : 0;
    207209   
     
    212214{
    213215    // MSIE extension - "object from which activation or the mouse pointer is exiting during the event" (huh?)
    214     if (type() != eventNames().mouseoutEvent)
     216    if (type() != eventNames().mouseoutEvent && type() != eventNames().mouseleaveEvent)
    215217        return relatedTarget() ? relatedTarget()->toNode() : 0;
    216218   
  • trunk/Source/WebCore/html/HTMLAttributeNames.in

    r148731 r149173  
    209209onloadstart
    210210onmousedown
     211onmouseenter
     212onmouseleave
    211213onmousemove
    212214onmouseout
  • trunk/Source/WebCore/html/HTMLElement.cpp

    r148373 r149173  
    227227        attributeNameToEventNameMap.set(ondblclickAttr.localName(), eventNames().dblclickEvent);
    228228        attributeNameToEventNameMap.set(onmousedownAttr.localName(), eventNames().mousedownEvent);
     229        attributeNameToEventNameMap.set(onmouseenterAttr.localName(), eventNames().mouseenterEvent);
     230        attributeNameToEventNameMap.set(onmouseleaveAttr.localName(), eventNames().mouseleaveEvent);
    229231        attributeNameToEventNameMap.set(onmousemoveAttr.localName(), eventNames().mousemoveEvent);
    230232        attributeNameToEventNameMap.set(onmouseoutAttr.localName(), eventNames().mouseoutEvent);
  • trunk/Source/WebCore/page/DOMWindow.h

    r148508 r149173  
    317317        DEFINE_ATTRIBUTE_EVENT_LISTENER(message);
    318318        DEFINE_ATTRIBUTE_EVENT_LISTENER(mousedown);
     319        DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseenter);
     320        DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseleave);
    319321        DEFINE_ATTRIBUTE_EVENT_LISTENER(mousemove);
    320322        DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseout);
  • trunk/Source/WebCore/page/DOMWindow.idl

    r148731 r149173  
    247247    attribute EventListener onmessage;
    248248    attribute EventListener onmousedown;
     249    attribute EventListener onmouseenter;
     250    attribute EventListener onmouseleave;
    249251    attribute EventListener onmousemove;
    250252    attribute EventListener onmouseout;
  • trunk/Source/WebCore/svg/SVGElement.cpp

    r148865 r149173  
    318318    else if (name == onmousedownAttr)
    319319        setAttributeEventListener(eventNames().mousedownEvent, createAttributeEventListener(this, name, value));
     320    else if (name == onmouseenterAttr)
     321        setAttributeEventListener(eventNames().mouseenterEvent, createAttributeEventListener(this, name, value));
     322    else if (name == onmouseleaveAttr)
     323        setAttributeEventListener(eventNames().mouseleaveEvent, createAttributeEventListener(this, name, value));
    320324    else if (name == onmousemoveAttr)
    321325        setAttributeEventListener(eventNames().mousemoveEvent, createAttributeEventListener(this, name, value));
  • trunk/Source/WebCore/svg/SVGElementInstance.h

    r141524 r149173  
    117117    DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(correspondingElement(), load);
    118118    DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(correspondingElement(), mousedown);
     119    DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(correspondingElement(), mouseenter);
     120    DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(correspondingElement(), mouseleave);
    119121    DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(correspondingElement(), mousemove);
    120122    DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(correspondingElement(), mouseout);
  • trunk/Source/WebCore/svg/SVGElementInstance.idl

    r141730 r149173  
    6363    attribute [NotEnumerable] EventListener onload;
    6464    attribute [NotEnumerable] EventListener onmousedown;
     65    attribute [NotEnumerable] EventListener onmouseenter;
     66    attribute [NotEnumerable] EventListener onmouseleave;
    6567    attribute [NotEnumerable] EventListener onmousemove;
    6668    attribute [NotEnumerable] EventListener onmouseout;
Note: See TracChangeset for help on using the changeset viewer.