Bug 716793. Dispatch synthetic mousemove off the refresh driver, not as fast as we can. r=roc

We use Flush_Display here because mousemoves flush out layout, so we want to do the synthetic one after we've done our normal layout flushing
This commit is contained in:
Boris Zbarsky 2012-01-10 00:23:29 -05:00
Родитель 218b374788
Коммит ec4e4ed1e5
10 изменённых файлов: 101 добавлений и 23 удалений

Просмотреть файл

@ -5246,7 +5246,8 @@ void PresShell::SynthesizeMouseMove(bool aFromScroll)
nsRefPtr<nsSynthMouseMoveEvent> ev =
new nsSynthMouseMoveEvent(this, aFromScroll);
if (NS_FAILED(NS_DispatchToCurrentThread(ev))) {
if (!GetPresContext()->RefreshDriver()->AddRefreshObserver(ev,
Flush_Display)) {
NS_WARNING("failed to dispatch nsSynthMouseMoveEvent");
return;
}

Просмотреть файл

@ -852,17 +852,28 @@ private:
// over our window or there is no last observed mouse location for some
// reason.
nsPoint mMouseLocation;
class nsSynthMouseMoveEvent : public nsRunnable {
class nsSynthMouseMoveEvent : public nsARefreshObserver {
public:
nsSynthMouseMoveEvent(PresShell* aPresShell, bool aFromScroll)
: mPresShell(aPresShell), mFromScroll(aFromScroll) {
NS_ASSERTION(mPresShell, "null parameter");
}
void Revoke() { mPresShell = nsnull; }
NS_IMETHOD Run() {
~nsSynthMouseMoveEvent() {
Revoke();
}
NS_INLINE_DECL_REFCOUNTING(nsSynthMouseMoveEvent)
void Revoke() {
if (mPresShell) {
mPresShell->GetPresContext()->RefreshDriver()->
RemoveRefreshObserver(this, Flush_Display);
mPresShell = nsnull;
}
}
virtual void WillRefresh(mozilla::TimeStamp aTime) {
if (mPresShell)
mPresShell->ProcessSynthMouseMoveEvent(mFromScroll);
return NS_OK;
}
private:
PresShell* mPresShell;

Просмотреть файл

@ -1,8 +1,10 @@
<!DOCTYPE html>
<html style="height: 100%">
<body style="height: 100%">
<!-- Button shouldn't get pointer events because it confuses tests if it
can be hovered -->
<button style="position: relative; display: table; width: 50%;
height: 50%; top: 25%; left: 25%">
height: 50%; top: 25%; left: 25%; pointer-events: none">
<div style="position: absolute; left: 0; right: 0; top: 0; bottom: 0;
background: green"></div>
</button>

Просмотреть файл

@ -12,8 +12,11 @@
</script>
</head>
<body style="height: 100%" onload="doIt()">
<!-- Button shouldn't get pointer events because it confuses tests if it
can be hovered -->
<button id="x" style="position: relative; display: table; width: 50%;
height: 50%; top: 25%; left: 25%">
height: 50%; top: 25%; left: 25%;
pointer-events: none">
</button>
</body>
</html>

Просмотреть файл

@ -1,8 +1,10 @@
<!DOCTYPE html>
<html style="height: 100%">
<body style="height: 100%">
<!-- Button shouldn't get pointer events because it confuses tests if it
can be hovered -->
<button style="position: relative; display: table-cell; width: 50%;
height: 50%; top: 25%; left: 25%">
height: 50%; top: 25%; left: 25%; pointer-events: none">
<div style="position: absolute; left: 0; right: 0; top: 0; bottom: 0;
background: green"></div>
</button>

Просмотреть файл

@ -12,8 +12,11 @@
</script>
</head>
<body style="height: 100%" onload="doIt()">
<!-- Button shouldn't get pointer events because it confuses tests if it
can be hovered -->
<button id="x" style="position: relative; display: table-cell; width: 50%;
height: 50%; top: 25%; left: 25%">
height: 50%; top: 25%; left: 25%;
pointer-events: none">
</button>
</body>
</html>

Просмотреть файл

@ -1,8 +1,10 @@
<!DOCTYPE html>
<html style="height: 100%">
<body style="height: 100%">
<!-- Button shouldn't get pointer events because it confuses tests if it
can be hovered -->
<button style="position: relative; display: table-row; width: 50%;
height: 50%; top: 25%; left: 25%">
height: 50%; top: 25%; left: 25%; pointer-events: none">
<div style="position: absolute; left: 0; right: 0; top: 0; bottom: 0;
background: green"></div>
</button>

Просмотреть файл

@ -12,8 +12,11 @@
</script>
</head>
<body style="height: 100%" onload="doIt()">
<!-- Button shouldn't get pointer events because it confuses tests if it
can be hovered -->
<button id="x" style="position: relative; display: table-row; width: 50%;
height: 50%; top: 25%; left: 25%">
height: 50%; top: 25%; left: 25%;
pointer-events: none">
</button>
</body>
</html>

Просмотреть файл

@ -135,9 +135,15 @@
function testMouse(x, y, msg, elem, win, exp, flags, callback) {
clearExpectedEvents();
var syntheticEvent = null;
exp.forEach(function (expEv) {
expEv.screenX = x;
expEv.screenY = y;
if (expEv.synthetic) {
is(syntheticEvent, null,
"Can't handle two synthetic events in a single testMouse call");
syntheticEvent = expEv;
}
gExpectedEvents.push(expEv);
});
printDebug("sending event: " + x + ", " + y + " (" + msg + ")\n");
@ -146,11 +152,23 @@
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
getInterface(Components.interfaces.nsIDOMWindowUtils);
utils.sendNativeMouseEvent(x, y, msg, flags || 0, elem);
gAfterLoopExecution = setTimeout(function () {
var callbackFunc = function() {
clearExpectedEvents();
callback();
}, 0);
}
if (syntheticEvent) {
// Set up this listener before we sendNativeMouseEvent, just
// in case that synchronously calls us.
eventListenOnce(syntheticEvent.target, syntheticEvent.type,
// Trigger callbackFunc async, so we're not assuming
// anything about how our listener gets ordered with
// others.
function () { SimpleTest.executeSoon(callbackFunc) });
}
utils.sendNativeMouseEvent(x, y, msg, flags || 0, elem);
if (!syntheticEvent) {
gAfterLoopExecution = setTimeout(callbackFunc, 0);
}
}
function eventListenOnce(elem, name, callback) {
@ -300,7 +318,7 @@
// Clicking an inactive window should make it active and fire a mouseover
// event.
[400, 150, NSLeftMouseDown, null, right, [
{ type: "mouseover", target: rightElem },
{ type: "mouseover", target: rightElem, synthetic: true },
]],
[400, 150, NSLeftMouseUp, null, right, [
]],
@ -343,7 +361,15 @@
function raiseLeftWindow(callback) {
clearExpectedEvents();
gExpectedEvents.push({ screenX: 150, screenY: 170, type: "mouseover", target: leftElem });
focusAndThen(left, function () { SimpleTest.executeSoon(callback); });
// We have to be a bit careful here. The synthetic mouse event may
// not fire for a bit after we focus the left window.
eventListenOnce(leftElem, "mouseover", function() {
// Trigger callback async, so we're not assuming
// anything about how our listener gets ordered with others.
SimpleTest.executeSoon(callback);
});
printDebug("focusing left window");
left.focus();
},
// It's active, so it should respond to mousemove events now.
[150, 170, NSMouseMoved, null, left, [
@ -384,7 +410,7 @@
// Activate the right window with a click.
// This will close the popup and make the mouse enter the right window.
[400, 180, NSLeftMouseDown, null, right, [
{ type: "mouseover", target: rightElem },
{ type: "mouseover", target: rightElem, synthetic: true },
]],
[400, 180, NSLeftMouseUp, null, right, [
]],

Просмотреть файл

@ -109,19 +109,44 @@ function test2() {
ok(!box.mozMatchesSelector(":hover"), "Box shouldn't be hovered (since the mouse isn't over it and since it's in a non-clickthrough iframe in a background window)");
// A function to waitForFocus and then wait for synthetic mouse
// events to happen. Note that those happen off the refresh driver,
// and happen after animation frame requests.
function changeFocusAndAwaitSyntheticMouse(callback, winToFocus,
elementToWatchForMouseEventOn) {
function mouseWatcher() {
elementToWatchForMouseEventOn.removeEventListener("mouseover",
mouseWatcher,
false);
elementToWatchForMouseEventOn.removeEventListener("mouseout",
mouseWatcher,
false);
SimpleTest.executeSoon(callback);
}
elementToWatchForMouseEventOn.addEventListener("mouseover",
mouseWatcher,
false);
elementToWatchForMouseEventOn.addEventListener("mouseout",
mouseWatcher,
false);
// Just pass a dummy function to waitForFocus; the mouseout/over listener
// will actually handle things for us.
SimpleTest.waitForFocus(function() {}, winToFocus);
}
// Move the mouse over the box.
moveMouseTo(100, 150, function () {
ok(!box.mozMatchesSelector(":hover"), "Box shouldn't be hovered (since it's in a non-clickthrough iframe in a background window)");
// Activate the left window.
SimpleTest.waitForFocus(function () {
changeFocusAndAwaitSyntheticMouse(function () {
ok(gIFrame.mozMatchesSelector(":hover"), "iframe should be hovered");
ok(box.mozMatchesSelector(":hover"), "Box should be hovered");
// De-activate the window (by activating the right window).
SimpleTest.waitForFocus(function () {
changeFocusAndAwaitSyntheticMouse(function () {
ok(!gIFrame.mozMatchesSelector(":hover"), "iframe shouldn't be hovered");
ok(!box.mozMatchesSelector(":hover"), "Box shouldn't be hovered");
// Re-activate it.
SimpleTest.waitForFocus(function () {
changeFocusAndAwaitSyntheticMouse(function () {
ok(gIFrame.mozMatchesSelector(":hover"), "iframe should be hovered");
ok(box.mozMatchesSelector(":hover"), "Box should be hovered");
// Unhover box and iframe by moving the mouse outside the window.
@ -130,9 +155,9 @@ function test2() {
ok(!box.mozMatchesSelector(":hover"), "box shouldn't be hovered");
finalize();
});
}, gLeftWindow);
}, gRightWindow);
}, gLeftWindow);
}, gLeftWindow, box);
}, gRightWindow, box);
}, gLeftWindow, box);
});
}