зеркало из https://github.com/mozilla/gecko-dev.git
Bug 479490 - 'ASSERTION: Mismatched calls to ResumeTimeouts'. r=bent, sr=jst, a=blocking1.9.1+
This commit is contained in:
Родитель
fe25d33f34
Коммит
e0648db07b
|
@ -6892,6 +6892,11 @@ nsDocument::CanSavePresentation(nsIRequest *aNewRequest)
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsPIDOMWindow* win = GetInnerWindow();
|
||||
if (win && win->TimeoutSuspendCount()) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// Check our event listener manager for unload/beforeunload listeners.
|
||||
nsCOMPtr<nsPIDOMEventTarget> piTarget = do_QueryInterface(mScriptGlobalObject);
|
||||
if (piTarget) {
|
||||
|
|
|
@ -145,6 +145,21 @@
|
|||
|
||||
#define NS_PROGRESS_EVENT_INTERVAL 50
|
||||
|
||||
class nsResumeTimeoutsEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsResumeTimeoutsEvent(nsPIDOMWindow* aWindow) : mWindow(aWindow) {}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mWindow->ResumeTimeouts(PR_FALSE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
};
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMEventListenerWrapper)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMEventListenerWrapper)
|
||||
|
@ -2793,15 +2808,14 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
|
|||
nsCOMPtr<nsIDOMWindow> topWindow;
|
||||
if (NS_SUCCEEDED(mOwner->GetTop(getter_AddRefs(topWindow)))) {
|
||||
nsCOMPtr<nsPIDOMWindow> suspendedWindow(do_QueryInterface(topWindow));
|
||||
if (suspendedWindow) {
|
||||
suspendedDoc = do_QueryInterface(suspendedWindow->GetExtantDocument());
|
||||
if (suspendedDoc) {
|
||||
suspendedDoc->SuppressEventHandling();
|
||||
}
|
||||
suspendedWindow->SuspendTimeouts();
|
||||
resumeTimeoutRunnable = NS_NEW_RUNNABLE_METHOD(nsPIDOMWindow,
|
||||
suspendedWindow.get(),
|
||||
ResumeTimeouts);
|
||||
if (suspendedWindow &&
|
||||
(suspendedWindow = suspendedWindow->GetCurrentInnerWindow())) {
|
||||
suspendedDoc = do_QueryInterface(suspendedWindow->GetExtantDocument());
|
||||
if (suspendedDoc) {
|
||||
suspendedDoc->SuppressEventHandling();
|
||||
}
|
||||
suspendedWindow->SuspendTimeouts(1, PR_FALSE);
|
||||
resumeTimeoutRunnable = new nsResumeTimeoutsEvent(suspendedWindow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6020,13 +6020,20 @@ nsDocShell::RestoreFromHistory()
|
|||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
|
||||
PRUint32 parentSuspendCount = 0;
|
||||
if (document) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> parent;
|
||||
GetParent(getter_AddRefs(parent));
|
||||
nsCOMPtr<nsIDOMDocument> parentDoc = do_GetInterface(parent);
|
||||
nsCOMPtr<nsIDocument> d = do_QueryInterface(parentDoc);
|
||||
if (d && d->EventHandlingSuppressed()) {
|
||||
document->SuppressEventHandling(d->EventHandlingSuppressed());
|
||||
if (d) {
|
||||
if (d->EventHandlingSuppressed()) {
|
||||
document->SuppressEventHandling(d->EventHandlingSuppressed());
|
||||
}
|
||||
nsCOMPtr<nsPIDOMWindow> parentWindow = d->GetWindow();
|
||||
if (parentWindow) {
|
||||
parentSuspendCount = parentWindow->TimeoutSuspendCount();
|
||||
}
|
||||
}
|
||||
|
||||
// Use the uri from the mLSHE we had when we entered this function
|
||||
|
@ -6116,6 +6123,13 @@ nsDocShell::RestoreFromHistory()
|
|||
}
|
||||
}
|
||||
|
||||
// If parent is suspended, increase suspension count.
|
||||
// This can't be done as early as event suppression since this
|
||||
// depends on docshell tree.
|
||||
if (parentSuspendCount) {
|
||||
privWin->SuspendTimeouts(parentSuspendCount, PR_FALSE);
|
||||
}
|
||||
|
||||
// Now that all of the child docshells have been put into place, we can
|
||||
// restart the timers for the window and all of the child frames.
|
||||
privWin->ResumeTimeouts();
|
||||
|
|
|
@ -76,8 +76,8 @@ class nsScriptObjectHolder;
|
|||
class nsXBLPrototypeHandler;
|
||||
|
||||
#define NS_PIDOMWINDOW_IID \
|
||||
{ 0x3d2b6b38, 0x810d, 0x4ac5, \
|
||||
{ 0x81, 0x7c, 0xb9, 0x70, 0x81, 0x80, 0x4d, 0x9f } }
|
||||
{ 0x80dd53b6, 0x8c61, 0x4dd6, \
|
||||
{ 0xb4, 0x51, 0xf7, 0xd7, 0x5c, 0xfc, 0x51, 0x96 } }
|
||||
|
||||
class nsPIDOMWindow : public nsIDOMWindowInternal
|
||||
{
|
||||
|
@ -272,11 +272,14 @@ public:
|
|||
virtual nsresult RestoreWindowState(nsISupports *aState) = 0;
|
||||
|
||||
// Suspend timeouts in this window and in child windows.
|
||||
virtual void SuspendTimeouts() = 0;
|
||||
virtual void SuspendTimeouts(PRUint32 aIncrease = 1,
|
||||
PRBool aFreezeChildren = PR_TRUE) = 0;
|
||||
|
||||
// Resume suspended timeouts in this window and in child windows.
|
||||
virtual nsresult ResumeTimeouts() = 0;
|
||||
|
||||
virtual nsresult ResumeTimeouts(PRBool aThawChildren = PR_TRUE) = 0;
|
||||
|
||||
virtual PRUint32 TimeoutSuspendCount() = 0;
|
||||
|
||||
// Fire any DOM notification events related to things that happened while
|
||||
// the window was frozen.
|
||||
virtual nsresult FireDelayedDOMEvents() = 0;
|
||||
|
|
|
@ -1885,6 +1885,14 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
if (st_id == nsIProgrammingLanguage::JAVASCRIPT)
|
||||
JS_EndRequest((JSContext *)this_ctx->GetNativeContext());
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> frame = do_QueryInterface(GetFrameElementInternal());
|
||||
if (frame && frame->GetOwnerDoc()) {
|
||||
nsPIDOMWindow* parentWindow = frame->GetOwnerDoc()->GetWindow();
|
||||
if (parentWindow && parentWindow->TimeoutSuspendCount()) {
|
||||
SuspendTimeouts(parentWindow->TimeoutSuspendCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Tell the contexts we have completed setting up the doc.
|
||||
NS_STID_FOR_ID(st_id) {
|
||||
|
@ -2054,7 +2062,7 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
|
|||
// Call FreeInnerObjects on all inner windows, not just the current
|
||||
// one, since some could be held by WindowStateHolder objects that
|
||||
// are GC-owned.
|
||||
for (nsGlobalWindow *inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
|
||||
for (nsRefPtr<nsGlobalWindow> inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
|
||||
inner != this;
|
||||
inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
|
||||
NS_ASSERTION(inner->mOuterWindow == this, "bad outer window pointer");
|
||||
|
@ -8389,37 +8397,39 @@ nsGlobalWindow::RestoreWindowState(nsISupports *aState)
|
|||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::SuspendTimeouts()
|
||||
nsGlobalWindow::SuspendTimeouts(PRUint32 aIncrease,
|
||||
PRBool aFreezeChildren)
|
||||
{
|
||||
FORWARD_TO_INNER_VOID(SuspendTimeouts, ());
|
||||
FORWARD_TO_INNER_VOID(SuspendTimeouts, (aIncrease, aFreezeChildren));
|
||||
|
||||
if (++mTimeoutsSuspendDepth != 1) {
|
||||
return;
|
||||
}
|
||||
PRBool suspended = (mTimeoutsSuspendDepth != 0);
|
||||
mTimeoutsSuspendDepth += aIncrease;
|
||||
|
||||
nsDOMThreadService* dts = nsDOMThreadService::get();
|
||||
if (dts) {
|
||||
dts->SuspendWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
|
||||
}
|
||||
|
||||
PRTime now = PR_Now();
|
||||
for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) {
|
||||
// Change mWhen to be the time remaining for this timer.
|
||||
if (t->mWhen > now)
|
||||
t->mWhen -= now;
|
||||
else
|
||||
t->mWhen = 0;
|
||||
|
||||
// Drop the XPCOM timer; we'll reschedule when restoring the state.
|
||||
if (t->mTimer) {
|
||||
t->mTimer->Cancel();
|
||||
t->mTimer = nsnull;
|
||||
|
||||
// Drop the reference that the timer's closure had on this timeout, we'll
|
||||
// add it back in ResumeTimeouts. Note that it shouldn't matter that we're
|
||||
// passing null for the context, since this shouldn't actually release this
|
||||
// timeout.
|
||||
t->Release();
|
||||
if (!suspended) {
|
||||
nsDOMThreadService* dts = nsDOMThreadService::get();
|
||||
if (dts) {
|
||||
dts->SuspendWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
|
||||
}
|
||||
|
||||
PRTime now = PR_Now();
|
||||
for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) {
|
||||
// Change mWhen to be the time remaining for this timer.
|
||||
if (t->mWhen > now)
|
||||
t->mWhen -= now;
|
||||
else
|
||||
t->mWhen = 0;
|
||||
|
||||
// Drop the XPCOM timer; we'll reschedule when restoring the state.
|
||||
if (t->mTimer) {
|
||||
t->mTimer->Cancel();
|
||||
t->mTimer = nsnull;
|
||||
|
||||
// Drop the reference that the timer's closure had on this timeout, we'll
|
||||
// add it back in ResumeTimeouts. Note that it shouldn't matter that we're
|
||||
// passing null for the context, since this shouldn't actually release this
|
||||
// timeout.
|
||||
t->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8439,12 +8449,11 @@ nsGlobalWindow::SuspendTimeouts()
|
|||
nsGlobalWindow *win =
|
||||
static_cast<nsGlobalWindow*>
|
||||
(static_cast<nsPIDOMWindow*>(pWin));
|
||||
|
||||
win->SuspendTimeouts();
|
||||
win->SuspendTimeouts(aIncrease, aFreezeChildren);
|
||||
|
||||
NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
|
||||
nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
|
||||
if (inner) {
|
||||
if (inner && aFreezeChildren) {
|
||||
inner->Freeze();
|
||||
}
|
||||
}
|
||||
|
@ -8453,67 +8462,68 @@ nsGlobalWindow::SuspendTimeouts()
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsGlobalWindow::ResumeTimeouts()
|
||||
nsGlobalWindow::ResumeTimeouts(PRBool aThawChildren)
|
||||
{
|
||||
FORWARD_TO_INNER(ResumeTimeouts, (), NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
NS_ASSERTION(mTimeoutsSuspendDepth, "Mismatched calls to ResumeTimeouts!");
|
||||
if (--mTimeoutsSuspendDepth != 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsDOMThreadService* dts = nsDOMThreadService::get();
|
||||
if (dts) {
|
||||
dts->ResumeWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
|
||||
}
|
||||
|
||||
// Restore all of the timeouts, using the stored time remaining
|
||||
// (stored in timeout->mWhen).
|
||||
|
||||
PRTime now = PR_Now();
|
||||
--mTimeoutsSuspendDepth;
|
||||
PRBool shouldResume = (mTimeoutsSuspendDepth == 0);
|
||||
nsresult rv;
|
||||
|
||||
#ifdef DEBUG
|
||||
PRBool _seenDummyTimeout = PR_FALSE;
|
||||
#endif
|
||||
|
||||
for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) {
|
||||
// There's a chance we're being called with RunTimeout on the stack in which
|
||||
// case we have a dummy timeout in the list that *must not* be resumed. It
|
||||
// can be identified by a null mWindow.
|
||||
if (!t->mWindow) {
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(!_seenDummyTimeout, "More than one dummy timeout?!");
|
||||
_seenDummyTimeout = PR_TRUE;
|
||||
#endif
|
||||
continue;
|
||||
if (shouldResume) {
|
||||
nsDOMThreadService* dts = nsDOMThreadService::get();
|
||||
if (dts) {
|
||||
dts->ResumeWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
|
||||
}
|
||||
|
||||
// Make sure to cast the unsigned PR_USEC_PER_MSEC to signed
|
||||
// PRTime to make the division do the right thing on 64-bit
|
||||
// platforms whether t->mWhen is positive or negative (which is
|
||||
// likely to always be positive here, but cast anyways for
|
||||
// consistency).
|
||||
PRUint32 delay =
|
||||
PR_MAX(((PRUint32)(t->mWhen / (PRTime)PR_USEC_PER_MSEC)),
|
||||
DOM_MIN_TIMEOUT_VALUE);
|
||||
// Restore all of the timeouts, using the stored time remaining
|
||||
// (stored in timeout->mWhen).
|
||||
|
||||
// Set mWhen back to the time when the timer is supposed to
|
||||
// fire.
|
||||
t->mWhen += now;
|
||||
PRTime now = PR_Now();
|
||||
|
||||
t->mTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
NS_ENSURE_TRUE(t->mTimer, NS_ERROR_OUT_OF_MEMORY);
|
||||
#ifdef DEBUG
|
||||
PRBool _seenDummyTimeout = PR_FALSE;
|
||||
#endif
|
||||
|
||||
rv = t->mTimer->InitWithFuncCallback(TimerCallback, t, delay,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
if (NS_FAILED(rv)) {
|
||||
t->mTimer = nsnull;
|
||||
return rv;
|
||||
for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) {
|
||||
// There's a chance we're being called with RunTimeout on the stack in which
|
||||
// case we have a dummy timeout in the list that *must not* be resumed. It
|
||||
// can be identified by a null mWindow.
|
||||
if (!t->mWindow) {
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(!_seenDummyTimeout, "More than one dummy timeout?!");
|
||||
_seenDummyTimeout = PR_TRUE;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make sure to cast the unsigned PR_USEC_PER_MSEC to signed
|
||||
// PRTime to make the division do the right thing on 64-bit
|
||||
// platforms whether t->mWhen is positive or negative (which is
|
||||
// likely to always be positive here, but cast anyways for
|
||||
// consistency).
|
||||
PRUint32 delay =
|
||||
PR_MAX(((PRUint32)(t->mWhen / (PRTime)PR_USEC_PER_MSEC)),
|
||||
DOM_MIN_TIMEOUT_VALUE);
|
||||
|
||||
// Set mWhen back to the time when the timer is supposed to
|
||||
// fire.
|
||||
t->mWhen += now;
|
||||
|
||||
t->mTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
NS_ENSURE_TRUE(t->mTimer, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = t->mTimer->InitWithFuncCallback(TimerCallback, t, delay,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
if (NS_FAILED(rv)) {
|
||||
t->mTimer = nsnull;
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Add a reference for the new timer's closure.
|
||||
t->AddRef();
|
||||
}
|
||||
|
||||
// Add a reference for the new timer's closure.
|
||||
t->AddRef();
|
||||
}
|
||||
|
||||
// Resume our children as well.
|
||||
|
@ -8536,11 +8546,11 @@ nsGlobalWindow::ResumeTimeouts()
|
|||
|
||||
NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
|
||||
nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
|
||||
if (inner) {
|
||||
if (inner && aThawChildren) {
|
||||
inner->Thaw();
|
||||
}
|
||||
|
||||
rv = win->ResumeTimeouts();
|
||||
rv = win->ResumeTimeouts(aThawChildren);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
@ -8549,6 +8559,13 @@ nsGlobalWindow::ResumeTimeouts()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsGlobalWindow::TimeoutSuspendCount()
|
||||
{
|
||||
FORWARD_TO_INNER(TimeoutSuspendCount, (), 0);
|
||||
return mTimeoutsSuspendDepth;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::GetScriptTypeID(PRUint32 *aScriptType)
|
||||
{
|
||||
|
|
|
@ -303,8 +303,10 @@ public:
|
|||
|
||||
virtual NS_HIDDEN_(nsresult) SaveWindowState(nsISupports **aState);
|
||||
virtual NS_HIDDEN_(nsresult) RestoreWindowState(nsISupports *aState);
|
||||
virtual NS_HIDDEN_(void) SuspendTimeouts();
|
||||
virtual NS_HIDDEN_(nsresult) ResumeTimeouts();
|
||||
virtual NS_HIDDEN_(void) SuspendTimeouts(PRUint32 aIncrease = 1,
|
||||
PRBool aFreezeChildren = PR_TRUE);
|
||||
virtual NS_HIDDEN_(nsresult) ResumeTimeouts(PRBool aThawChildren = PR_TRUE);
|
||||
virtual NS_HIDDEN_(PRUint32) TimeoutSuspendCount();
|
||||
virtual NS_HIDDEN_(nsresult) FireDelayedDOMEvents();
|
||||
virtual NS_HIDDEN_(PRBool) IsFrozen() const
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче