Bug 675121. Unregister animation frame callbacks from the refresh driver while we have event handling suppressed. r=smaug,roc

This commit is contained in:
Boris Zbarsky 2011-08-07 22:24:28 -04:00
Родитель 027ba1376c
Коммит 4793353c33
6 изменённых файлов: 91 добавлений и 19 удалений

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

@ -1331,6 +1331,10 @@ public:
PRUint32 EventHandlingSuppressed() const { return mEventsSuppressed; }
bool IsEventHandlingEnabled() {
return !EventHandlingSuppressed() && mScriptGlobalObject;
}
/**
* Increment the number of external scripts being evaluated.
*/

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

@ -3196,9 +3196,7 @@ nsDocument::doCreateShell(nsPresContext* aContext,
mExternalResourceMap.ShowViewers();
if (mScriptGlobalObject) {
RescheduleAnimationFrameNotifications();
}
MaybeRescheduleAnimationFrameNotifications();
shell.swap(*aInstancePtrResult);
@ -3206,8 +3204,13 @@ nsDocument::doCreateShell(nsPresContext* aContext,
}
void
nsDocument::RescheduleAnimationFrameNotifications()
nsDocument::MaybeRescheduleAnimationFrameNotifications()
{
if (!mPresShell || !IsEventHandlingEnabled()) {
// bail out for now, until one of those conditions changes
return;
}
nsRefreshDriver* rd = mPresShell->GetPresContext()->RefreshDriver();
if (mHavePendingPaint) {
rd->ScheduleBeforePaintEvent(this);
@ -3228,7 +3231,7 @@ void
nsDocument::DeleteShell()
{
mExternalResourceMap.HideViewers();
if (mScriptGlobalObject) {
if (IsEventHandlingEnabled()) {
RevokeAnimationFrameNotifications();
}
mPresShell = nsnull;
@ -3776,7 +3779,7 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
// our layout history state now.
mLayoutHistoryState = GetLayoutHistoryState();
if (mPresShell) {
if (mPresShell && !EventHandlingSuppressed()) {
RevokeAnimationFrameNotifications();
}
@ -3837,9 +3840,7 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
}
}
if (mPresShell) {
RescheduleAnimationFrameNotifications();
}
MaybeRescheduleAnimationFrameNotifications();
}
// Remember the pointer to our window (or lack there of), to avoid
@ -7648,6 +7649,10 @@ SuppressEventHandlingInDocument(nsIDocument* aDocument, void* aData)
void
nsDocument::SuppressEventHandling(PRUint32 aIncrease)
{
if (mEventsSuppressed == 0 && aIncrease != 0 && mPresShell &&
mScriptGlobalObject) {
RevokeAnimationFrameNotifications();
}
mEventsSuppressed += aIncrease;
EnumerateSubDocuments(SuppressEventHandlingInDocument, &aIncrease);
}
@ -7807,13 +7812,8 @@ GetAndUnsuppressSubDocuments(nsIDocument* aDocument, void* aData)
void
nsDocument::UnsuppressEventHandlingAndFireEvents(PRBool aFireEvents)
{
if (mEventsSuppressed > 0) {
--mEventsSuppressed;
}
nsTArray<nsCOMPtr<nsIDocument> > documents;
documents.AppendElement(this);
EnumerateSubDocuments(GetAndUnsuppressSubDocuments, &documents);
GetAndUnsuppressSubDocuments(this, &documents);
if (aFireEvents) {
NS_DispatchToCurrentThread(new nsDelayedEventDispatcher(documents));
@ -8042,7 +8042,7 @@ nsIDocument::ScheduleBeforePaintEvent(nsIAnimationFrameListener* aListener)
if (aListener) {
PRBool alreadyRegistered = !mAnimationFrameListeners.IsEmpty();
if (mAnimationFrameListeners.AppendElement(aListener) &&
!alreadyRegistered && mPresShell) {
!alreadyRegistered && mPresShell && IsEventHandlingEnabled()) {
mPresShell->GetPresContext()->RefreshDriver()->
ScheduleAnimationFrameListeners(this);
}
@ -8056,6 +8056,7 @@ nsIDocument::ScheduleBeforePaintEvent(nsIAnimationFrameListener* aListener)
// event will fire, or we'll quietly go away at some point.
mHavePendingPaint =
!mPresShell ||
!IsEventHandlingEnabled() ||
mPresShell->GetPresContext()->RefreshDriver()->
ScheduleBeforePaintEvent(this);
}

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

@ -865,7 +865,10 @@ public:
virtual void UnsuppressEventHandlingAndFireEvents(PRBool aFireEvents);
void DecreaseEventSuppression() { --mEventsSuppressed; }
void DecreaseEventSuppression() {
--mEventsSuppressed;
MaybeRescheduleAnimationFrameNotifications();
}
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsDocument,
nsIDocument)
@ -1149,8 +1152,9 @@ private:
// Revoke any pending notifications due to mozRequestAnimationFrame calls
void RevokeAnimationFrameNotifications();
// Reschedule any notifications we need to handle mozRequestAnimationFrame
void RescheduleAnimationFrameNotifications();
// Reschedule any notifications we need to handle
// mozRequestAnimationFrame, if it's OK to do so.
void MaybeRescheduleAnimationFrameNotifications();
// These are not implemented and not supported.
nsDocument(const nsDocument& aOther);

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

@ -501,6 +501,8 @@ _TEST_FILES2 = \
delayedServerEvents.sjs \
test_bug664916.html \
test_bug666604.html \
test_bug675121.html \
file_bug675121.sjs \
$(NULL)
_CHROME_FILES = \

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

@ -0,0 +1,15 @@
var timer;
function handleRequest(request, response)
{
response.setHeader("Cache-Control", "no-cache", false);
response.setHeader("Content-Type", "text/plain", false);
response.write("Responded");
response.processAsync();
timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
timer.initWithCallback(function() {
response.finish();
// 50ms certainly be enough for one refresh driver firing to happen!
}, 50, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
}

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

@ -0,0 +1,46 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=675121
-->
<head>
<title>Test for Bug 675121</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=675121">Mozilla Bug 675121</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 675121 **/
var callbackFired = false;
var xhrInProgress = false;
function f() {
callbackFired = true;
if (!xhrInProgress) {
SimpleTest.finish();
}
}
window.mozRequestAnimationFrame(f);
var xhr = new XMLHttpRequest();
xhr.open("GET", "file_bug675121.sjs", false);
xhrInProgress = true;
xhr.send();
xhrInProgress = false;
is(xhr.responseText, "Responded", "Should have a response by now");
is(callbackFired, false, "Callback should not fire during sync XHR");
if (!callbackFired) {
SimpleTest.waitForExplicitFinish();
}
</script>
</pre>
</body>
</html>