mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 478536 Crash by removing a scroll target in MozMouseScrollFailed event handler r+sr=roc
This commit is contained in:
parent
810c9a7d8c
commit
80fc6e44f1
@ -377,6 +377,8 @@ public:
|
||||
static void BeginTransaction(nsIFrame* aTargetFrame,
|
||||
PRInt32 aNumLines,
|
||||
PRBool aScrollHorizontal);
|
||||
// Be careful, UpdateTransaction may fire a DOM event, therefore, the target
|
||||
// frame might be destroyed in the event handler.
|
||||
static PRBool UpdateTransaction(PRInt32 aNumLines,
|
||||
PRBool aScrollHorizontal);
|
||||
static void EndTransaction();
|
||||
@ -543,6 +545,10 @@ nsMouseWheelTransaction::OnFailToScrollTarget()
|
||||
sTargetFrame->GetContent(),
|
||||
NS_LITERAL_STRING("MozMouseScrollFailed"),
|
||||
PR_TRUE, PR_TRUE);
|
||||
// The target frame might be destroyed in the event handler, at that time,
|
||||
// we need to finish the current transaction
|
||||
if (!sTargetFrame)
|
||||
EndTransaction();
|
||||
}
|
||||
|
||||
void
|
||||
@ -2734,6 +2740,12 @@ nsEventStateManager::DoScrollText(nsPresContext* aPresContext,
|
||||
nsIScrollableViewProvider* svp = do_QueryFrame(lastScrollFrame);
|
||||
if (svp && (scrollView = svp->GetScrollableView())) {
|
||||
nsMouseWheelTransaction::UpdateTransaction(aNumLines, aScrollHorizontal);
|
||||
// When the scroll event will not scroll any views, UpdateTransaction
|
||||
// fired MozMouseScrollFailed event which is for automated testing.
|
||||
// In the event handler, the target frame might be destroyed. Then,
|
||||
// we should not keep handling this scroll event.
|
||||
if (!nsMouseWheelTransaction::GetTargetFrame())
|
||||
return NS_OK;
|
||||
} else {
|
||||
nsMouseWheelTransaction::EndTransaction();
|
||||
lastScrollFrame = nsnull;
|
||||
|
@ -60,6 +60,8 @@ include $(topsrcdir)/config/rules.mk
|
||||
_TEST_FILES = test_bug343416.xul \
|
||||
test_bug444800.xul \
|
||||
test_bug462106.xul \
|
||||
test_bug478536.xul \
|
||||
window_bug478536.xul \
|
||||
test_keycodes.xul \
|
||||
test_wheeltransaction.xul \
|
||||
window_wheeltransaction.xul \
|
||||
|
36
widget/tests/test_bug478536.xul
Normal file
36
widget/tests/test_bug478536.xul
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=478536
|
||||
-->
|
||||
<window title="Mozilla Bug 478536"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<title>Test for Bug 478536</title>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
window.open("window_bug478536.xul", "_blank",
|
||||
"chrome,width=600,height=600");
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
</window>
|
204
widget/tests/window_bug478536.xul
Normal file
204
widget/tests/window_bug478536.xul
Normal file
@ -0,0 +1,204 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<window title="Mozilla Bug 478536"
|
||||
width="600" height="600"
|
||||
onload="onload();"
|
||||
onunload="onunload();"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml" id="body">
|
||||
<style type="text/css">
|
||||
#view {
|
||||
overflow: auto;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 1px solid;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
<pre id="view" onscroll="onScrollView(event);">
|
||||
Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
|
||||
Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
|
||||
Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
|
||||
Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
|
||||
Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
|
||||
Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
|
||||
Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
|
||||
Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
|
||||
Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
|
||||
Text. Text. Text. Text. Text. Text. Text. Text. Text. Text. Text.
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
function ok(aCondition, aMessage)
|
||||
{
|
||||
window.opener.wrappedJSObject.SimpleTest.ok(aCondition, aMessage);
|
||||
}
|
||||
|
||||
function is(aLeft, aRight, aMessage)
|
||||
{
|
||||
window.opener.wrappedJSObject.SimpleTest.is(aLeft, aRight, aMessage);
|
||||
}
|
||||
|
||||
function isnot(aLeft, aRight, aMessage)
|
||||
{
|
||||
window.opener.wrappedJSObject.SimpleTest.isnot(aLeft, aRight, aMessage);
|
||||
}
|
||||
|
||||
var gBody = document.getElementById("body");
|
||||
var gView = document.getElementById("view");
|
||||
|
||||
/**
|
||||
* Description:
|
||||
*
|
||||
* First, lock the wheel scrolling target to "view" at first step.
|
||||
* Next, scroll back to top most of the "view" at second step.
|
||||
* Finally, scroll back again at third step. This fails to scroll the "view",
|
||||
* then, |onMouseScrollFailed| event should be fired. And at that time, we
|
||||
* can remove the "view". So, in post processing of the event firere, the
|
||||
* "view" should not be referred.
|
||||
*
|
||||
* For suppressing random test failure, all tests will be retried if we handle
|
||||
* unexpected timeout event.
|
||||
*/
|
||||
|
||||
var gTests = [
|
||||
{ scrollToForward: true, shouldScroll: true },
|
||||
{ scrollToForward: false, shouldScroll: true },
|
||||
{ scrollToForward: false, shouldScroll: false }
|
||||
];
|
||||
var gCurrentTestIndex = -1;
|
||||
var gIgnoreScrollEvent = true;
|
||||
|
||||
var gPrefSvc = Components.classes["@mozilla.org/preferences-service;1"].
|
||||
getService(Components.interfaces.nsIPrefBranch2);
|
||||
const kPrefNameTimeout = "mousewheel.transaction.timeout";
|
||||
const kDefaultTimeout = gPrefSvc.getIntPref(kPrefNameTimeout);
|
||||
|
||||
var gTimeout = kDefaultTimeout;
|
||||
|
||||
gBody.addEventListener("MozMouseScrollFailed", onMouseScrollFailed, false);
|
||||
gBody.addEventListener("MozMouseScrollTransactionTimeout",
|
||||
onTransactionTimeout, false);
|
||||
|
||||
function setTimeoutPrefs(aTimeout)
|
||||
{
|
||||
gPrefSvc.setIntPref(kPrefNameTimeout, aTimeout);
|
||||
gTimeout = aTimeout;
|
||||
}
|
||||
|
||||
function resetTimeoutPrefs()
|
||||
{
|
||||
if (gTimeout == kDefaultTimeout)
|
||||
return;
|
||||
setTimeoutPrefs(kDefaultTimeout);
|
||||
}
|
||||
|
||||
function growUpTimeoutPrefs()
|
||||
{
|
||||
if (gTimeout != kDefaultTimeout)
|
||||
return;
|
||||
setTimeoutPrefs(5000);
|
||||
}
|
||||
|
||||
function onload()
|
||||
{
|
||||
disableNonTestMouseEvents(true);
|
||||
setTimeout(runNextTest, 0);
|
||||
}
|
||||
|
||||
function onunload()
|
||||
{
|
||||
resetTimeoutPrefs();
|
||||
disableNonTestMouseEvents(false);
|
||||
window.opener.wrappedJSObject.SimpleTest.finish();
|
||||
}
|
||||
|
||||
function finish()
|
||||
{
|
||||
window.close();
|
||||
}
|
||||
|
||||
// testing code
|
||||
|
||||
var gTimer;
|
||||
function clearTimer()
|
||||
{
|
||||
clearTimeout(gTimer);
|
||||
gTimer = 0;
|
||||
}
|
||||
|
||||
function runNextTest()
|
||||
{
|
||||
clearTimer();
|
||||
if (++gCurrentTestIndex >= gTests.length) {
|
||||
ok(true, "didn't crash, succeeded");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
fireWheelScrollEvent(gTests[gCurrentTestIndex].scrollToForward);
|
||||
}
|
||||
|
||||
var gRetryCount = 5;
|
||||
function retryAllTests()
|
||||
{
|
||||
clearTimer();
|
||||
if (--gRetryCount >= 0) {
|
||||
gView.scrollTop = 0;
|
||||
gView.scrollLeft = 0;
|
||||
gCurrentTestIndex = -1;
|
||||
growUpTimeoutPrefs();
|
||||
ok(true, "WARNING: retry current test-list...");
|
||||
gTimer = setTimeout(runNextTest, 0);
|
||||
} else {
|
||||
ok(false, "Failed by unexpected timeout");
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
function fireWheelScrollEvent(aForward)
|
||||
{
|
||||
gIgnoreScrollEvent = false;
|
||||
var event = { axis: "vertical", delta: aForward ? 4 : -4,
|
||||
type: "DOMMouseScroll" };
|
||||
synthesizeMouseScroll(gView, 5, 5, event, window);
|
||||
}
|
||||
|
||||
function onScrollView(aEvent)
|
||||
{
|
||||
if (gIgnoreScrollEvent)
|
||||
return;
|
||||
gIgnoreScrollEvent = true;
|
||||
clearTimer();
|
||||
ok(gTests[gCurrentTestIndex].shouldScroll, "The view is scrolled");
|
||||
gTimer = setTimeout(runNextTest, 0);
|
||||
}
|
||||
|
||||
function onMouseScrollFailed(aEvent)
|
||||
{
|
||||
clearTimer();
|
||||
gIgnoreScrollEvent = true;
|
||||
ok(!gTests[gCurrentTestIndex].shouldScroll, "The view is not scrolled");
|
||||
if (!gTests[gCurrentTestIndex].shouldScroll)
|
||||
gBody.removeChild(gView);
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
function onTransactionTimeout(aEvent)
|
||||
{
|
||||
if (!gTimer)
|
||||
return;
|
||||
gIgnoreScrollEvent = true;
|
||||
retryAllTests();
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
</window>
|
Loading…
Reference in New Issue
Block a user