Commit 1f71fdfa authored by ap's avatar ap
Browse files

Reviewed by Darin.

        - http://bugzilla.opendarwin.org/show_bug.cgi?id=3439
         mouseover effects can get stuck sometimes due to missing events
        - http://bugzilla.opendarwin.org/show_bug.cgi?id=7701
         mouseout sent to the wrong element when layout changes simultaneously
        
        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.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@13402 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 2bff9a8b
2006-03-20 Alexey Proskuryakov <ap@nypop.com>
Reviewed by Darin.
- http://bugzilla.opendarwin.org/show_bug.cgi?id=3439
mouseover effects can get stuck sometimes due to missing events
- http://bugzilla.opendarwin.org/show_bug.cgi?id=5764
DIV mouseOver and mouseOut triggered too often
- http://bugzilla.opendarwin.org/show_bug.cgi?id=7701
mouseout sent to the wrong element when layout changes simultaneously
* fast/events/mouseover-mouseout-expected.txt: Added.
* fast/events/mouseover-mouseout.html: Added.
* fast/events/mouseover-mouseout2-expected.txt: Added.
* fast/events/mouseover-mouseout2.html: Added.
2006-03-20 Beth Dakin <bdakin@apple.com>
 
Reviewed by Adele
......
EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of P > BODY > HTML > #document to 0 of P > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
Tests for bugs 3439, 5764, 7701 - Mouse events vs. DOM manipulation.
Move the mouse pointer from left to right:
1              
1              
2
3
4
5
Log Expected results
mouseover on t1_1
mouseout on t1_1
mouseover on t1_2
mouseout on t1_2
mouseover on t2_1
mouseout on t2_1
mouseover on t2_2
mouseout on t2_2
mouseover on t3_1
mouseover on t3_2
mouseout on t3_2
mouseover on t4_1
mouseover on t4_2
mouseout on t4_2
mouseover on t5_1
mouseout on t5_1
mouseover on t5_2
mouseout on t5_2
mouseover on frame6
mouseover on t6
mouseout on t6
mouseout on frame6
mouseover on t1_1
mouseout on t1_1
mouseover on t1_2
mouseout on t1_2
mouseover on t2_1
mouseout on t2_1
mouseover on t2_2
mouseout on t2_2
mouseover on t3_1
mouseover on t3_2
mouseout on t3_2
mouseover on t4_1
mouseover on t4_2
mouseout on t4_2
mouseover on t5_1
mouseout on t5_1
mouseover on t5_2
mouseout on t5_2
mouseover on frame6
mouseover on t6
mouseout on t6
mouseout on frame6
SUCCESS
<html>
<body onload="autoTest()">
<script>
function log(message)
{
var item = document.createElement("li");
item.appendChild(document.createTextNode(message));
document.getElementById('log').appendChild(item);
}
function logMouseEvent(evt)
{
target = (evt.target) ? evt.target : evt.srcElement;
log(evt.type + " on " + target.id);
}
</script>
<p>Tests for bugs
<a href="http://bugzilla.opendarwin.org/show_bug.cgi?id=3439">3439</a>,
<a href="http://bugzilla.opendarwin.org/show_bug.cgi?id=5764">5764</a>,
<a href="http://bugzilla.opendarwin.org/show_bug.cgi?id=7701">7701</a> -
Mouse events vs. DOM manipulation.</p>
<p>Move the mouse pointer from left to right:</p>
<!-- 1: Show an element under the mouse -->
<div style='height: 50; width: 50; background:red;top:100;left:100; position:absolute;' id='t1_1'
onMouseOver="logMouseEvent(event); document.getElementById('t1_2').style.display = 'block'"
onMouseOut="logMouseEvent(event);">1&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; </div>
<div style='display: none; height: 50; width: 50; background:white;top:100;left:100; position:absolute;' id='t1_2'
onMouseOver="logMouseEvent(event)"
onMouseOut="logMouseEvent(event); document.getElementById('t1_2').style.backgroundColor = 'gray'">1&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; </div>
<!-- 2: Hide an element under the mouse -->
<div style='height: 50; width: 50; background:white;top:100;left:150; position:absolute;' id='t2_2'
onMouseOver="logMouseEvent(event)"
onMouseOut="logMouseEvent(event); document.getElementById('t2_2').style.backgroundColor = 'gray'">2</div>
<div style='height: 50; width: 50; background:orange;top:100;left:150; position:absolute;' id='t2_1'
onMouseOver="logMouseEvent(event); document.getElementById('t2_1').style.display = 'none'"
onMouseOut="logMouseEvent(event)">2</div>
<!-- 3: Move the element under the mouse into another document -->
<div style='height: 50; width: 50; background:white;top:100;left:200; position:absolute;' id='t3_2'
onMouseOver="logMouseEvent(event)"
onMouseOut="logMouseEvent(event); document.getElementById('t3_2').style.backgroundColor = 'gray'">3</div>
<div style='height: 50; width: 50; background:yellow;top:100;left:200; position:absolute;' id='t3_1'
onMouseOver="
logMouseEvent(event);
newDoc = document.getElementById('invisible_frame').document;
if (!newDoc)
newDoc = document.getElementById('invisible_frame').contentDocument;
try {
newDoc.adoptNode(document.getElementById('t3_1'));
} catch (e) {
newDoc.documentElement.appendChild(document.getElementById('t3_1'));
}
"
onMouseOut="logMouseEvent(event)">3</div>
<!-- 4: Move the element under the mouse into another document, and append it -->
<div style='height: 50; width: 50; background:white;top:100;left:250; position:absolute;' id='t4_2'
onMouseOver="logMouseEvent(event)"
onMouseOut="logMouseEvent(event); document.getElementById('t4_2').style.backgroundColor = 'gray'">4</div>
<div style='height: 50; width: 50; background:green;top:100;left:250; position:absolute;' id='t4_1'
onMouseOver="
logMouseEvent(event);
newDoc = document.getElementById('invisible_frame').document;
if (!newDoc)
newDoc = document.getElementById('invisible_frame').contentDocument;
try {
newDoc.documentElement.appendChild(newDoc.adoptNode(document.getElementById('t4_1')));
} catch (ex) {
newDoc.documentElement.appendChild(document.getElementById('t4_1'));
}
"
onMouseOut="logMouseEvent(event)">4</div>
<!-- 5: Remove the element under the mouse -->
<div style='height: 50; width: 50; background:white;top:100;left:300; position:absolute;' id='t5_2'
onMouseOver="logMouseEvent(event)"
onMouseOut="logMouseEvent(event); document.getElementById('t5_2').style.backgroundColor = 'gray'">5</div>
<div style='height: 50; width: 50; background:blue;top:100;left:300; position:absolute;' id='t5_1'
onMouseOver="
logMouseEvent(event);
document.body.removeChild(document.getElementById('t5_1'));
"
onMouseOut="logMouseEvent(event)">5</div>
<!-- 6: Enter a different document -->
<iframe style='height: 50; width: 50; top:100;left:350; position:absolute; border-width:0' src='data:text/html,
<body style="margin-left:0; margin-top:0">
<script>
function log(message)
{
var item = top.document.createElement("li");
item.appendChild(document.createTextNode(message));
top.document.getElementById("log").appendChild(item);
}
function logMouseEvent(evt)
{
target = (evt.target) ? evt.target : evt.srcElement;
log(evt.type + " on " + target.id);
}
function doOnMouseOver(evt)
{
logMouseEvent(evt);
document.getElementById("t6").style.backgroundColor = "white";
}
function doOnMouseOut(evt)
{
logMouseEvent(evt);
document.getElementById("t6").style.backgroundColor = "gray";
}
</script>
<div style="height: 50; width: 50; background:violet; top:0;left:0; position:absolute;" id="t6"
onMouseOver="doOnMouseOver(event);"
onMouseOut="doOnMouseOut(event)">6</div>
</body>'
onMouseOver="logMouseEvent(event)"
onMouseOut="
logMouseEvent(event);
if (top.document.getElementById('log').innerHTML == top.document.getElementById('exp').innerHTML) {
top.document.getElementById('success').style.display = 'block';
}
"
id="frame6"
></iframe>
<iframe id=invisible_frame style="width:0; height:0; border-width:0"></iframe>
<table border=1 width="100%" style='top:200; position:absolute'>
<tr><td width="50%">Log</td><td>Expected results</td></tr>
<tr>
<td id=log style="vertical-align:top"></td>
<td id=exp style="vertical-align:top"><li>mouseover on t1_1</li><li>mouseout on t1_1</li><li>mouseover on t1_2</li><li>mouseout on t1_2</li><li>mouseover on t2_1</li><li>mouseout on t2_1</li><li>mouseover on t2_2</li><li>mouseout on t2_2</li><li>mouseover on t3_1</li><li>mouseover on t3_2</li><li>mouseout on t3_2</li><li>mouseover on t4_1</li><li>mouseover on t4_2</li><li>mouseout on t4_2</li><li>mouseover on t5_1</li><li>mouseout on t5_1</li><li>mouseover on t5_2</li><li>mouseout on t5_2</li><li>mouseover on frame6</li><li>mouseover on t6</li><li>mouseout on t6</li><li>mouseout on frame6</li></td>
</tr>
</table>
<div style='height: 50; width: 300; top:100;left:100; position:absolute; display:none' id='success'><br><center>SUCCESS</center></div>
<script>
function autoTest() {
if (window.layoutTestController) {
layoutTestController.dumpAsText();
eventSender.mouseMoveTo(1,1);
eventSender.mouseDown();
eventSender.mouseUp();
eventSender.mouseMoveTo(125, 125);
eventSender.mouseMoveTo(130, 125);
eventSender.mouseMoveTo(135, 125);
eventSender.mouseMoveTo(175, 125);
eventSender.mouseMoveTo(180, 125);
eventSender.mouseMoveTo(225, 125);
eventSender.mouseMoveTo(230, 125);
eventSender.mouseMoveTo(275, 125);
eventSender.mouseMoveTo(280, 125);
eventSender.mouseMoveTo(325, 125);
eventSender.mouseMoveTo(330, 125);
eventSender.mouseMoveTo(375, 125);
eventSender.mouseMoveTo(380, 125);
eventSender.mouseMoveTo(385, 125);
eventSender.mouseMoveTo(1, 1);
}
}
</script>
</body>
</html>
EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of P > BODY > HTML > #document to 0 of P > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
Tests for bugs 3439, 5764, 7701 - Mouse events vs. DOM manipulation.
Move the mouse pointer from left to right:
3
4
5
6
Log Expected results
mouseover on frame1
mouseover on t1
mouseout on t1
mouseout on frame1
mouseover on frame2
mouseover on t2
mouseout on t2
mouseout on frame2
mouseover on frame3
mouseover on t3_1
mouseout on frame3
mouseover on t3_2
mouseout on t3_2
mouseover on t4_2
mouseout on t4_2
mouseover on frame4
mouseover on t4_1
mouseout on t4_1
mouseout on frame4
mouseover on frame5
mouseover on t5_1
mouseout on frame5
mouseover on t5_2
mouseout on t5_2
mouseover on t6
mouseout on t6
mouseover on frame1
mouseover on t1
mouseout on t1
mouseout on frame1
mouseover on frame2
mouseover on t2
mouseout on t2
mouseout on frame2
mouseover on frame3
mouseover on t3_1
mouseout on frame3
mouseover on t3_2
mouseout on t3_2
mouseover on t4_2
mouseout on t4_2
mouseover on frame4
mouseover on t4_1
mouseout on t4_1
mouseout on frame4
mouseover on frame5
mouseover on t5_1
mouseout on frame5
mouseover on t5_2
mouseout on t5_2
mouseover on t6
mouseout on t6
SUCCESS
<html>
<body onload="autoTest()">
<script>
function log(message)
{
var item = document.createElement("li");
item.appendChild(document.createTextNode(message));
document.getElementById('log').appendChild(item);
}
function logMouseEvent(evt)
{
target = (evt.target) ? evt.target : evt.srcElement;
log(evt.type + " on " + target.id);
}
</script>
<p>Tests for bugs
<a href="http://bugzilla.opendarwin.org/show_bug.cgi?id=3439">3439</a>,
<a href="http://bugzilla.opendarwin.org/show_bug.cgi?id=5764">5764</a>,
<a href="http://bugzilla.opendarwin.org/show_bug.cgi?id=7701">7701</a> -
Mouse events vs. DOM manipulation.</p>
<p>Move the mouse pointer from left to right:</p>
<!-- 1: Enter a subframe -->
<iframe style='height: 50; width: 50; top:100;left:100; position:absolute; border-width:0' src='data:text/html,
<body style="margin-left:0; margin-top:0">
<script>
function log(message)
{
var item = top.document.createElement("li");
item.appendChild(document.createTextNode(message));
top.document.getElementById("log").appendChild(item);
}
function logMouseEvent(evt)
{
target = (evt.target) ? evt.target : evt.srcElement;
log(evt.type + " on " + target.id);
}
function doOnMouseOver(evt)
{
logMouseEvent(evt);
document.getElementById("t1").style.backgroundColor = "white";
}
function doOnMouseOut(evt)
{
logMouseEvent(evt);
document.getElementById("t1").style.backgroundColor = "gray";
}
</script>
<div style="height: 50; width: 50; background:red; top:0;left:0; position:absolute;" id="t1"
onMouseOver="doOnMouseOver(event);"
onMouseOut="doOnMouseOut(event)">1</div>
</body>'
onMouseOver="logMouseEvent(event)"
onMouseOut="logMouseEvent(event);"
id="frame1"
></iframe>
<!-- 2: Move from one subframe to another -->
<iframe style='height: 50; width: 50; top:100;left:150; position:absolute; border-width:0' src='data:text/html,
<body style="margin-left:0; margin-top:0">
<script>
function log(message)
{
var item = top.document.createElement("li");
item.appendChild(document.createTextNode(message));
top.document.getElementById("log").appendChild(item);
}
function logMouseEvent(evt)
{
target = (evt.target) ? evt.target : evt.srcElement;
log(evt.type + " on " + target.id);
}
function doOnMouseOver(evt)
{
logMouseEvent(evt);
document.getElementById("t2").style.backgroundColor = "white";
}
function doOnMouseOut(evt)
{
logMouseEvent(evt);
document.getElementById("t2").style.backgroundColor = "gray";
}
</script>
<div style="height: 50; width: 50; background:orange; top:0;left:0; position:absolute;" id="t2"
onMouseOver="doOnMouseOver(event);"
onMouseOut="doOnMouseOut(event)">2</div>
</body>'
onMouseOver="logMouseEvent(event)"
onMouseOut="logMouseEvent(event)"
id="frame2"
></iframe>
<!-- 3: Hide a subframe under the mouse -->
<div style='height: 50; width: 50; background:white;top:100;left:200; position:absolute;' id='t3_2'
onMouseOver="logMouseEvent(event)"
onMouseOut="logMouseEvent(event); document.getElementById('t3_2').style.backgroundColor = 'gray'">3</div>
<iframe style='height: 50; width: 50; top:100;left:200; position:absolute; border-width:0' src='data:text/html,
<body style="margin-left:0; margin-top:0">
<script>
function log(message)
{
var item = top.document.createElement("li");
item.appendChild(document.createTextNode(message));
top.document.getElementById("log").appendChild(item);
}
function logMouseEvent(evt)
{
target = (evt.target) ? evt.target : evt.srcElement;
log(evt.type + " on " + target.id);
}
function doOnMouseOver(evt)
{
logMouseEvent(evt);
top.document.getElementById("frame3").style.display = "none";
}
</script>
<div style="height: 50; width: 50; background:yellow; top:0;left:0; position:absolute;" id="t3_1"
onMouseOver="doOnMouseOver(event);"
onMouseOut="logMouseEvent(event)">3</div>
</body>'
onMouseOver="logMouseEvent(event)"
onMouseOut="logMouseEvent(event)"
id="frame3"
></iframe>
<!-- 4: Show a subframe under the mouse -->
<div style='height: 50; width: 50; background:green;top:100;left:250; position:absolute;' id='t4_2'
onMouseOver="logMouseEvent(event); document.getElementById('frame4').style.visibility = 'visible'"
onMouseOut="logMouseEvent(event)">4</div>
<iframe style='height: 50; width: 50; top:100;left:250; position:absolute; border-width:0; visibility:hidden' src='data:text/html,
<body style="margin-left:0; margin-top:0">
<script>
function log(message)
{
var item = top.document.createElement("li");
item.appendChild(document.createTextNode(message));
top.document.getElementById("log").appendChild(item);
}
function logMouseEvent(evt)
{
target = (evt.target) ? evt.target : evt.srcElement;
log(evt.type + " on " + target.id);
}
function doOnMouseOut(evt)
{
logMouseEvent(evt);
document.getElementById("t4_1").style.backgroundColor = "gray";
}
</script>
<div style="height: 50; width: 50; background:white; top:0;left:0; position:absolute;" id="t4_1"
onMouseOver="logMouseEvent(event);"
onMouseOut="doOnMouseOut(event)">4</div>
</body>'
onMouseOver="logMouseEvent(event)"
onMouseOut="logMouseEvent(event)"
id="frame4"
></iframe>
<!-- 5: Remove the subframe under the mouse -->
<div style='height: 50; width: 50; background:white;top:100;left:300; position:absolute;' id='t5_2'
onMouseOver="logMouseEvent(event)"
onMouseOut="logMouseEvent(event); document.getElementById('t5_2').style.backgroundColor = 'gray'">5</div>
<iframe style='height: 50; width: 50; top:100;left:300; position:absolute; border-width:0' src='data:text/html,
<body style="margin-left:0; margin-top:0">
<script>
function log(message)
{
var item = top.document.createElement("li");
item.appendChild(document.createTextNode(message));
top.document.getElementById("log").appendChild(item);
}
function logMouseEvent(evt)
{
target = (evt.target) ? evt.target : evt.srcElement;
log(evt.type + " on " + target.id);
}
function doOnMouseOver(evt)
{
logMouseEvent(evt);
top.document.body.removeChild(top.document.getElementById("frame5"));
}
</script>
<div style="height: 50; width: 50; background:blue; top:0;left:0; position:absolute;" id="t5_1"
onMouseOver="doOnMouseOver(event);"
onMouseOut="logMouseEvent(event)">5</div>
</body>'
onMouseOver="logMouseEvent(event)"
onMouseOut="logMouseEvent(event)"
id="frame5"
></iframe>
<!-- 6: Nothing but a rainbow end -->
<div style='height: 50; width: 50; background:violet;top:100;left:350; position:absolute;' id='t6'
onMouseOver="logMouseEvent(event); document.getElementById('t6').style.backgroundColor = 'white'"
onMouseOut="
logMouseEvent(event);
document.getElementById('t6').style.backgroundColor = 'gray';
if (top.document.getElementById('log').innerHTML == top.document.getElementById('exp').innerHTML) {
top.document.getElementById('success').style.display = 'block';
}
">6</div>
<table border=1 width="100%" style='top:200; position:absolute'>
<tr><td width="50%">Log</td><td>Expected results</td></tr>
<tr>
<td id=log style="vertical-align:top"></td>
<td id=exp style="vertical-align:top"><LI>mouseover on frame1</LI><LI>mouseover on t1</LI><LI>mouseout on t1</LI><LI>mouseout on frame1</LI><LI>mouseover on frame2</LI><LI>mouseover on t2</LI><LI>mouseout on t2</LI><LI>mouseout on frame2</LI><LI>mouseover on frame3</LI><LI>mouseover on t3_1</LI><LI>mouseout on frame3</LI><LI>mouseover on t3_2</LI><LI>mouseout on t3_2</LI><LI>mouseover on t4_2</LI><LI>mouseout on t4_2</LI><LI>mouseover on frame4</LI><LI>mouseover on t4_1</LI><LI>mouseout on t4_1</LI><LI>mouseout on frame4</LI><LI>mouseover on frame5</LI><LI>mouseover on t5_1</LI><LI>mouseout on frame5</LI><LI>mouseover on t5_2</LI><LI>mouseout on t5_2</LI><LI>mouseover on t6</LI><LI>mouseout on t6</LI></td>
</tr>
</table>
<div style='height: 50; width: 300; top:100;left:100; position:absolute; display:none' id='success'><br><center>SUCCESS</center></div>
<script>
function autoTest() {
if (window.layoutTestController) {
layoutTestController.dumpAsText();
layoutTestController.waitUntilDone();
eventSender.mouseMoveTo(1,1);
eventSender.mouseDown();
eventSender.mouseUp();
eventSender.mouseMoveTo(125, 125);
eventSender.mouseMoveTo(130, 125);
eventSender.mouseMoveTo(135, 125);
eventSender.mouseMoveTo(175, 125);
eventSender.mouseMoveTo(180, 125);
eventSender.mouseMoveTo(225, 125);
eventSender.mouseMoveTo(230, 125);
eventSender.mouseMoveTo(275, 125);
eventSender.mouseMoveTo(280, 125);
eventSender.mouseMoveTo(325, 125);
eventSender.mouseMoveTo(330, 125);
eventSender.mouseMoveTo(375, 125);
eventSender.mouseMoveTo(380, 125);
eventSender.mouseMoveTo(385, 125);
eventSender.mouseMoveTo(1, 1);
layoutTestController.notifyDone()
}
}
</script>
</body>
</html>
2006-03-20 Alexey Proskuryakov <ap@nypop.com>
Reviewed by Darin.
- http://bugzilla.opendarwin.org/show_bug.cgi?id=3439
mouseover effects can get stuck sometimes due to missing events
- http://bugzilla.opendarwin.org/show_bug.cgi?id=7701