Changeset 13402 in webkit


Ignore:
Timestamp:
Mar 20, 2006 12:46:24 PM (18 years ago)
Author:
ap
Message:

Reviewed by Darin.


Implemented saving the previous node under the mouse, so that we don't need to
recalculate it, which is slow and even not really possible. This has fixed a number
of issues with mouse event dispatching when the content changes.
The code still needs refactoring and cleanup, see bug 3439 for comments.

Tests (both files perform multiple checks):

  • fast/events/mouseover-mouseout.html
  • fast/events/mouseover-mouseout2.html
  • page/Frame.h: Added a Frame parameter to passSubframeEventToSubframe(), used for mouseMoved events.
  • bridge/mac/FrameMac.h: Ditto.
  • bridge/mac/FrameMac.mm: (WebCore::FrameMac::passSubframeEventToSubframe): Use the passed subframe to target NSMouseMoved events.
  • page/FrameView.h: Added a prepareMouseEvent() helper that does viewportToContents translation.
  • page/FrameView.cpp: Added data members for storing the previous node and subframe under the mouse to FrameViewPrivate. Removed the now unused prevMouseX/prevMouseY. (WebCore::FrameViewPrivate::reset): Reset the new data members. (WebCore::subframeForEvent): A temporary place for the code that extracts a subframe pointer from MouseEventWithHitTestResults, moved from FrameMac::passSubframeEventToSubframe(). (WebCore::FrameView::prepareMouseEvent): The new helper. (WebCore::FrameView::handleMousePressEvent): Use the new helper. (WebCore::FrameView::handleMouseDoubleClickEvent): Ditto. (WebCore::FrameView::handleMouseReleaseEvent): Ditto. (WebCore::FrameView::updateDragAndDrop): Ditto. (WebCore::FrameView::hoverTimerFired): Ditto. (WebCore::FrameView::dispatchMouseEvent): Store and use the oldUnder node, don't store or use prevMouseX/Y. (WebCore::FrameView::handleMouseMoveEvent): Rewrote dispatching events to subframes using a stored oldSubframe reference. Protect "this" from being removed while in this function.
Location:
trunk
Files:
4 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r13401 r13402  
     12006-03-20  Alexey Proskuryakov  <ap@nypop.com>
     2
     3        Reviewed by Darin.
     4
     5        - http://bugzilla.opendarwin.org/show_bug.cgi?id=3439
     6         mouseover effects can get stuck sometimes due to missing events
     7        - http://bugzilla.opendarwin.org/show_bug.cgi?id=5764
     8         DIV mouseOver and mouseOut triggered too often
     9        - http://bugzilla.opendarwin.org/show_bug.cgi?id=7701
     10         mouseout sent to the wrong element when layout changes simultaneously
     11
     12        * fast/events/mouseover-mouseout-expected.txt: Added.
     13        * fast/events/mouseover-mouseout.html: Added.
     14        * fast/events/mouseover-mouseout2-expected.txt: Added.
     15        * fast/events/mouseover-mouseout2.html: Added.
     16
    1172006-03-20  Beth Dakin  <bdakin@apple.com>
    218
  • trunk/WebCore/ChangeLog

    r13400 r13402  
     12006-03-20  Alexey Proskuryakov  <ap@nypop.com>
     2
     3        Reviewed by Darin.
     4
     5        - http://bugzilla.opendarwin.org/show_bug.cgi?id=3439
     6         mouseover effects can get stuck sometimes due to missing events
     7        - http://bugzilla.opendarwin.org/show_bug.cgi?id=7701
     8         mouseout sent to the wrong element when layout changes simultaneously
     9       
     10        Implemented saving the previous node under the mouse, so that we don't need to
     11        recalculate it, which is slow and even not really possible. This has fixed a number
     12        of issues with mouse event dispatching when the content changes.
     13        The code still needs refactoring and cleanup, see bug 3439 for comments.
     14
     15        Tests (both files perform multiple checks):
     16        - fast/events/mouseover-mouseout.html
     17        - fast/events/mouseover-mouseout2.html
     18
     19        * page/Frame.h: Added a Frame parameter to passSubframeEventToSubframe(),
     20        used for mouseMoved events.
     21        * bridge/mac/FrameMac.h: Ditto.
     22        * bridge/mac/FrameMac.mm:
     23        (WebCore::FrameMac::passSubframeEventToSubframe): Use the passed subframe to target
     24        NSMouseMoved events.
     25        * page/FrameView.h: Added a prepareMouseEvent() helper that does viewportToContents translation.
     26        * page/FrameView.cpp: Added data members for storing the previous node and subframe
     27        under the mouse to FrameViewPrivate. Removed the now unused prevMouseX/prevMouseY.
     28        (WebCore::FrameViewPrivate::reset): Reset the new data members.
     29        (WebCore::subframeForEvent): A temporary place for the code that extracts a subframe
     30        pointer from MouseEventWithHitTestResults, moved from FrameMac::passSubframeEventToSubframe().
     31        (WebCore::FrameView::prepareMouseEvent): The new helper.
     32        (WebCore::FrameView::handleMousePressEvent): Use the new helper.
     33        (WebCore::FrameView::handleMouseDoubleClickEvent): Ditto.
     34        (WebCore::FrameView::handleMouseReleaseEvent): Ditto.
     35        (WebCore::FrameView::updateDragAndDrop): Ditto.
     36        (WebCore::FrameView::hoverTimerFired): Ditto.
     37        (WebCore::FrameView::dispatchMouseEvent): Store and use the oldUnder node, don't store
     38        or use prevMouseX/Y.
     39        (WebCore::FrameView::handleMouseMoveEvent): Rewrote dispatching events to subframes using
     40        a stored oldSubframe reference. Protect "this" from being removed while in this function.
     41
    1422006-03-20  Darin Adler  <darin@apple.com>
    243
  • trunk/WebCore/bridge/mac/FrameMac.h

    r13396 r13402  
    230230
    231231    virtual bool passMouseDownEventToWidget(Widget *);
    232     virtual bool passSubframeEventToSubframe(MouseEventWithHitTestResults &);
     232    virtual bool passSubframeEventToSubframe(MouseEventWithHitTestResults&, Frame* subframePart);
    233233    virtual bool passWheelEventToChildWidget(Node *);
    234234   
  • trunk/WebCore/bridge/mac/FrameMac.mm

    r13396 r13402  
    18321832}
    18331833
    1834 bool FrameMac::passSubframeEventToSubframe(MouseEventWithHitTestResults &event)
     1834bool FrameMac::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframePart)
    18351835{
    18361836    BEGIN_BLOCK_OBJC_EXCEPTIONS;
     
    18381838    switch ([_currentEvent type]) {
    18391839        case NSMouseMoved: {
    1840             Node *node = event.innerNode();
    1841             if (!node)
    1842                 return false;
    1843             RenderObject *renderer = node->renderer();
    1844             if (!renderer || !renderer->isWidget())
    1845                 return false;
    1846             Widget *widget = static_cast<RenderWidget *>(renderer)->widget();
    1847             if (!widget || !widget->isFrameView())
    1848                 return false;
    1849             Frame *subframePart = static_cast<FrameView *>(widget)->frame();
    1850             if (!subframePart)
    1851                 return false;
     1840            ASSERT(subframePart);
    18521841            [Mac(subframePart)->bridge() mouseMoved:_currentEvent];
    18531842            return true;
  • trunk/WebCore/page/Frame.h

    r13396 r13402  
    592592  virtual void submitForm(const ResourceRequest&) = 0;
    593593  virtual void urlSelected(const ResourceRequest&) = 0;
    594   virtual bool passSubframeEventToSubframe(MouseEventWithHitTestResults&) = 0;
     594  virtual bool passSubframeEventToSubframe(MouseEventWithHitTestResults&, Frame* subframePart = 0) = 0;
    595595  virtual bool passWheelEventToChildWidget(Node *) = 0;
    596596  virtual bool lastEventIsMouseUp() const = 0;
  • trunk/WebCore/page/FrameView.cpp

    r13397 r13402  
    7777    {
    7878        underMouse = 0;
     79        oldUnder = 0;
     80        oldSubframe = 0;
    7981        linkPressed = false;
    8082        useSlowRepaints = false;
     
    8587        borderX = 30;
    8688        borderY = 30;
    87         prevMouseX = -1;
    88         prevMouseY = -1;
    8989        clickCount = 0;
    9090        clickNode = 0;
     
    105105
    106106    RefPtr<Node> underMouse;
     107    RefPtr<Node> oldUnder;
     108    RefPtr<Frame> oldSubframe;
    107109
    108110    bool borderTouched : 1;
     
    122124    RefPtr<Node> clickNode;
    123125
    124     int prevMouseX, prevMouseY;
    125126    bool scrollingSelf;
    126127    Timer<FrameView> layoutTimer;
     
    464465/////////////////
    465466
     467static Frame* subframeForEvent(const MouseEventWithHitTestResults& mev)
     468{
     469    if (!mev.innerNode())
     470        return 0;
     471
     472    RenderObject* renderer = mev.innerNode()->renderer();
     473    if (!renderer || !renderer->isWidget())
     474        return 0;
     475
     476    Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
     477    if (!widget || !widget->isFrameView())
     478        return 0;
     479
     480    return static_cast<FrameView*>(widget)->frame();
     481}
     482
    466483void FrameView::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
    467484{
     
    471488    RefPtr<FrameView> protector(this);
    472489
    473     int xm, ym;
    474     viewportToContents(mouseEvent.x(), mouseEvent.y(), xm, ym);
    475 
    476490    d->mousePressed = true;
    477491
    478     MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(false, true, false, xm, ym, mouseEvent);
     492    MouseEventWithHitTestResults mev = prepareMouseEvent(false, true, false, mouseEvent);
    479493
    480494    if (m_frame->passSubframeEventToSubframe(mev)) {
     
    507521    RefPtr<FrameView> protector(this);
    508522
    509     int xm, ym;
    510     viewportToContents(mouseEvent.x(), mouseEvent.y(), xm, ym);
    511 
    512523    // We get this instead of a second mouse-up
    513524    d->mousePressed = false;
    514525
    515     MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(false, true, false, xm, ym, mouseEvent);
     526    MouseEventWithHitTestResults mev = prepareMouseEvent(false, true, false, mouseEvent);
    516527
    517528    if (m_frame->passSubframeEventToSubframe(mev))
     
    602613        return;
    603614
     615    RefPtr<FrameView> protector(this);
     616   
    604617    if (d->hoverTimer.isActive())
    605618        d->hoverTimer.stop();
    606 
    607     int xm, ym;
    608     viewportToContents(mouseEvent.x(), mouseEvent.y(), xm, ym);
    609619
    610620    if (d->resizingFrameSet) {
     
    617627    // This means that :hover and :active freeze in the state they were in when the mouse
    618628    // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down.
    619     MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(d->mousePressed && m_frame->mouseDownMayStartSelect(),
    620         d->mousePressed, true, xm, ym, mouseEvent);
    621 
    622     if (!m_frame->passSubframeEventToSubframe(mev))
    623         setCursor(selectCursor(mev, m_frame.get(), d->mousePressed));
    624        
     629    MouseEventWithHitTestResults mev = prepareMouseEvent(d->mousePressed && m_frame->mouseDownMayStartSelect(),
     630        d->mousePressed, true, mouseEvent);
     631
     632    if (d->oldSubframe)
     633        m_frame->passSubframeEventToSubframe(mev, d->oldSubframe.get());
     634
    625635    bool swallowEvent = dispatchMouseEvent(mousemoveEvent, mev.innerNode(), false, 0, mouseEvent, true);
    626636    if (!swallowEvent)
    627637        m_frame->handleMouseMoveEvent(mev);
     638   
     639    RefPtr<Frame> newSubframe = subframeForEvent(mev);
     640   
     641    if (newSubframe && d->oldSubframe != newSubframe)
     642        m_frame->passSubframeEventToSubframe(mev, newSubframe.get());
     643    else
     644        setCursor(selectCursor(mev, m_frame.get(), d->mousePressed));
     645   
     646    d->oldSubframe = newSubframe;
    628647}
    629648
     
    641660    RefPtr<FrameView> protector(this);
    642661
    643     int xm, ym;
    644     viewportToContents(mouseEvent.x(), mouseEvent.y(), xm, ym);
    645 
    646662    d->mousePressed = false;
    647663
     
    651667    }
    652668
    653     MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(false, false, false, xm, ym, mouseEvent);
     669    MouseEventWithHitTestResults mev = prepareMouseEvent(false, false, false, mouseEvent);
    654670
    655671    if (m_frame->passSubframeEventToSubframe(mev))
     
    686702{
    687703    bool accept = false;
    688     int xm, ym;
    689     viewportToContents(event.x(), event.y(), xm, ym);
    690     MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(true, false, false, xm, ym, PlatformMouseEvent());
     704
     705    MouseEventWithHitTestResults mev = prepareMouseEvent(true, false, false, PlatformMouseEvent());
    691706
    692707    // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
     
    925940}
    926941
     942MouseEventWithHitTestResults FrameView::prepareMouseEvent(bool readonly, bool active, bool mouseMove, const PlatformMouseEvent& mev)
     943{
     944    ASSERT(m_frame);
     945    ASSERT(m_frame->document());
     946   
     947    int xm, ym;
     948    viewportToContents(mev.x(), mev.y(), xm, ym);
     949
     950    return m_frame->document()->prepareMouseEvent(readonly, active, mouseMove, xm, ym, mev);
     951}
     952
    927953bool FrameView::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool cancelable,
    928954    int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
     
    935961    // mouseout/mouseover
    936962    if (setUnder) {
    937         int clientX, clientY;
    938         viewportToContents(mouseEvent.x(), mouseEvent.y(), clientX, clientY);
    939         if (d->prevMouseX != clientX || d->prevMouseY != clientY) {
    940             // ### this code sucks. we should save the oldUnder instead of calculating
    941             // it again. calculating is expensive! (Dirk)
    942             // Also, there's no guarantee that the old under node is even around any more,
    943             // so we could be sending a mouseout to a node that never got a mouseover.
    944             RefPtr<Node> oldUnder;
    945             if (d->prevMouseX >= 0) {
    946                 oldUnder = m_frame->document()->prepareMouseEvent(true, false, true,
    947                     d->prevMouseX, d->prevMouseY, mouseEvent).innerNode();
    948                 if (oldUnder && oldUnder->isTextNode())
    949                     oldUnder = oldUnder->parentNode();
    950             }
    951             d->prevMouseX = clientX;
    952             d->prevMouseY = clientY;
    953             if (oldUnder != targetNode) {
    954                 // send mouseout event to the old node
    955                 if (oldUnder)
    956                     EventTargetNodeCast(oldUnder.get())->dispatchMouseEvent(mouseEvent, mouseoutEvent, 0, targetNode);
    957                 // send mouseover event to the new node
    958                 if (targetNode)
    959                     EventTargetNodeCast(targetNode)->dispatchMouseEvent(mouseEvent, mouseoverEvent, 0, oldUnder.get());
    960             }
     963        if (d->oldUnder && d->oldUnder->getDocument() != frame()->document())
     964            d->oldUnder = 0;
     965
     966        if (d->oldUnder != targetNode) {
     967            // send mouseout event to the old node
     968            if (d->oldUnder)
     969                EventTargetNodeCast(d->oldUnder.get())->dispatchMouseEvent(mouseEvent, mouseoutEvent, 0, targetNode);
     970            // send mouseover event to the new node
     971            if (targetNode)
     972                EventTargetNodeCast(targetNode)->dispatchMouseEvent(mouseEvent, mouseoverEvent, 0, d->oldUnder.get());
    961973        }
     974        d->oldUnder = targetNode;
    962975    }
    963976
     
    10521065{
    10531066    d->hoverTimer.stop();
    1054     m_frame->document()->prepareMouseEvent(false, false, true, d->prevMouseX, d->prevMouseY, PlatformMouseEvent());
     1067    prepareMouseEvent(false, false, true, PlatformMouseEvent());
    10551068}
    10561069
  • trunk/WebCore/page/FrameView.h

    r13393 r13402  
    5555class FrameMac;
    5656class PlatformMouseEvent;
     57class MouseEventWithHitTestResults;
    5758class Node;
    5859class RenderBox;
     
    216217    void addFormCompletionItem(const DeprecatedString &name, const DeprecatedString &value);
    217218
     219    MouseEventWithHitTestResults prepareMouseEvent(bool readonly, bool active, bool mouseMove, const PlatformMouseEvent&);
     220
    218221    bool dispatchMouseEvent(const AtomicString& eventType, Node* target,
    219222        bool cancelable, int clickCount, const PlatformMouseEvent&, bool setUnder);
Note: See TracChangeset for help on using the changeset viewer.