Fix for bug 430624 (Crash [@ nsDocShellEditorData::DetachFromWindow] with spellcheck attribute). Patch by cpearce, r=peterv, sr=jst.

git-svn-id: svn://10.0.0.236/trunk@251098 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
peterv%propagandism.org 2008-05-02 11:36:31 +00:00
parent f1b88a235a
commit 12abbe164f
11 changed files with 124 additions and 72 deletions

View File

@ -3971,6 +3971,10 @@ nsHTMLDocument::SetEditingState(EditingState aState)
nsresult nsresult
nsHTMLDocument::EditingStateChanged() nsHTMLDocument::EditingStateChanged()
{ {
if (mRemovedFromDocShell) {
return NS_OK;
}
if (mEditingState == eSettingUp || mEditingState == eTearingDown) { if (mEditingState == eSettingUp || mEditingState == eTearingDown) {
// XXX We shouldn't recurse. // XXX We shouldn't recurse.
return NS_OK; return NS_OK;

View File

@ -1011,11 +1011,8 @@ nsDocShell::FirePageHideNotification(PRBool aIsUnload)
kids[i]->FirePageHideNotification(aIsUnload); kids[i]->FirePageHideNotification(aIsUnload);
} }
} }
}
// Now make sure our editor, if any, is detached before we go // Now make sure our editor, if any, is detached before we go
// any farther. // any farther.
if (mEditorData && aIsUnload) {
DetachEditorFromWindow(); DetachEditorFromWindow();
} }
@ -3377,11 +3374,6 @@ nsDocShell::Reload(PRUint32 aReloadFlags)
} }
// Need to purge detached editor here, else when we reload a page,
// the detached editor state causes SetDesignMode() to fail.
if (mOSHE)
mOSHE->SetEditorData(nsnull);
return rv; return rv;
} }
@ -4885,8 +4877,13 @@ nsDocShell::Embed(nsIContentViewer * aContentViewer,
SetBaseUrlForWyciwyg(aContentViewer); SetBaseUrlForWyciwyg(aContentViewer);
} }
// XXX What if SetupNewViewer fails? // XXX What if SetupNewViewer fails?
if (mLSHE) if (mLSHE) {
// Restore the editing state, if it's stored in session history.
if (mLSHE->HasDetachedEditor()) {
ReattachEditorToWindow(mLSHE);
}
SetHistoryEntry(&mOSHE, mLSHE); SetHistoryEntry(&mOSHE, mLSHE);
}
PRBool updateHistory = PR_TRUE; PRBool updateHistory = PR_TRUE;
@ -5332,29 +5329,20 @@ nsDocShell::CanSavePresentation(PRUint32 aLoadType,
return PR_TRUE; return PR_TRUE;
} }
PRBool
nsDocShell::HasDetachedEditor()
{
return (mOSHE && mOSHE->HasDetachedEditor()) ||
(mLSHE && mLSHE->HasDetachedEditor());
}
void void
nsDocShell::ReattachEditorToWindow(nsIDOMWindow *aWindow, nsISHEntry *aSHEntry) nsDocShell::ReattachEditorToWindow(nsISHEntry *aSHEntry)
{ {
NS_ASSERTION(!mEditorData, NS_ASSERTION(!mEditorData,
"Why reattach an editor when we already have one?"); "Why reattach an editor when we already have one?");
NS_ASSERTION(aWindow, NS_ASSERTION(aSHEntry && aSHEntry->HasDetachedEditor(),
"Need a window to reattach to.");
NS_ASSERTION(HasDetachedEditor(),
"Reattaching when there's not a detached editor."); "Reattaching when there's not a detached editor.");
if (mEditorData || !aWindow || !aSHEntry) if (mEditorData || !aSHEntry)
return; return;
mEditorData = aSHEntry->ForgetEditorData(); mEditorData = aSHEntry->ForgetEditorData();
if (mEditorData) { if (mEditorData) {
nsresult res = mEditorData->ReattachToWindow(aWindow); nsresult res = mEditorData->ReattachToWindow(this);
NS_ASSERTION(NS_SUCCEEDED(res), "Failed to reattach editing session"); NS_ASSERTION(NS_SUCCEEDED(res), "Failed to reattach editing session");
} }
} }
@ -5362,18 +5350,21 @@ nsDocShell::ReattachEditorToWindow(nsIDOMWindow *aWindow, nsISHEntry *aSHEntry)
void void
nsDocShell::DetachEditorFromWindow(nsISHEntry *aSHEntry) nsDocShell::DetachEditorFromWindow(nsISHEntry *aSHEntry)
{ {
if (!aSHEntry || !mEditorData) if (!mEditorData)
return; return;
NS_ASSERTION(!aSHEntry->HasDetachedEditor(), NS_ASSERTION(!aSHEntry || !aSHEntry->HasDetachedEditor(),
"Why detach an editor twice?"); "Detaching editor when it's already detached.");
nsresult res = mEditorData->DetachFromWindow(); nsresult res = mEditorData->DetachFromWindow();
NS_ASSERTION(NS_SUCCEEDED(res), "Failed to detach editor"); NS_ASSERTION(NS_SUCCEEDED(res), "Failed to detach editor");
if (NS_SUCCEEDED(res)) { if (NS_SUCCEEDED(res)) {
// Make aSHEntry hold the owning ref to the editor data. // Make aSHEntry hold the owning ref to the editor data.
if (aSHEntry)
aSHEntry->SetEditorData(mEditorData.forget()); aSHEntry->SetEditorData(mEditorData.forget());
else
mEditorData = nsnull;
} }
#ifdef DEBUG #ifdef DEBUG
@ -5390,6 +5381,7 @@ nsDocShell::DetachEditorFromWindow(nsISHEntry *aSHEntry)
void void
nsDocShell::DetachEditorFromWindow() nsDocShell::DetachEditorFromWindow()
{ {
if (mOSHE)
DetachEditorFromWindow(mOSHE); DetachEditorFromWindow(mOSHE);
} }
@ -5542,6 +5534,10 @@ nsDocShell::FinishRestore()
} }
} }
if (mOSHE && mOSHE->HasDetachedEditor()) {
ReattachEditorToWindow(mOSHE);
}
if (mContentViewer) { if (mContentViewer) {
nsCOMPtr<nsIDOMDocument> domDoc; nsCOMPtr<nsIDOMDocument> domDoc;
mContentViewer->GetDOMDocument(getter_AddRefs(domDoc)); mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
@ -6010,11 +6006,6 @@ nsDocShell::RestoreFromHistory()
} }
} }
if (HasDetachedEditor()) {
nsCOMPtr<nsIDOMWindow> domWin = do_QueryInterface(privWin);
ReattachEditorToWindow(domWin, mLSHE);
}
// Simulate the completion of the load. // Simulate the completion of the load.
nsDocShell::FinishRestore(); nsDocShell::FinishRestore();
@ -7153,10 +7144,6 @@ nsDocShell::InternalLoad(nsIURI * aURI,
mLoadType = aLoadType; mLoadType = aLoadType;
// Detach the current editor so that it can be restored from the
// bfcache later.
DetachEditorFromWindow();
// mLSHE should be assigned to aSHEntry, only after Stop() has // mLSHE should be assigned to aSHEntry, only after Stop() has
// been called. But when loading an error page, do not clear the // been called. But when loading an error page, do not clear the
// mLSHE for the real page. // mLSHE for the real page.
@ -7221,22 +7208,6 @@ nsDocShell::InternalLoad(nsIURI * aURI,
DisplayLoadError(rv, aURI, nsnull, chan); DisplayLoadError(rv, aURI, nsnull, chan);
} }
if (aSHEntry) {
if (aLoadType & LOAD_CMD_HISTORY) {
// We've just loaded a page from session history. Reattach
// its editing session if it has one.
nsCOMPtr<nsIDOMWindow> domWin;
CallGetInterface(this, static_cast<nsIDOMWindow**>(getter_AddRefs(domWin)));
ReattachEditorToWindow(domWin, aSHEntry);
} else {
// This is a non-history load from a session history entry. Purge any
// previous editing sessions, so that the the editing session will
// be recreated. This can happen when we reload something that's
// in the bfcache.
aSHEntry->SetEditorData(nsnull);
}
}
return rv; return rv;
} }
@ -8735,8 +8706,11 @@ nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel * aChannel)
NS_IMETHODIMP nsDocShell::GetEditor(nsIEditor * *aEditor) NS_IMETHODIMP nsDocShell::GetEditor(nsIEditor * *aEditor)
{ {
NS_ENSURE_ARG_POINTER(aEditor); NS_ENSURE_ARG_POINTER(aEditor);
nsresult rv = EnsureEditorData();
if (NS_FAILED(rv)) return rv; if (!mEditorData) {
*aEditor = nsnull;
return NS_OK;
}
return mEditorData->GetEditor(aEditor); return mEditorData->GetEditor(aEditor);
} }
@ -9043,9 +9017,12 @@ nsDocShell::EnsureScriptEnvironment()
NS_IMETHODIMP NS_IMETHODIMP
nsDocShell::EnsureEditorData() nsDocShell::EnsureEditorData()
{ {
NS_ASSERTION(!HasDetachedEditor(), "EnsureEditorData() called when detached.\n"); PRBool openDocHasDetachedEditor = mOSHE && mOSHE->HasDetachedEditor();
if (!mEditorData && !mIsBeingDestroyed && !openDocHasDetachedEditor) {
if (!mEditorData && !mIsBeingDestroyed && !HasDetachedEditor()) { // We shouldn't recreate the editor data if it already exists, or
// we're shutting down, or we already have a detached editor data
// stored in the session history. We should only have one editordata
// per docshell.
mEditorData = new nsDocShellEditorData(this); mEditorData = new nsDocShellEditorData(this);
} }

View File

@ -525,7 +525,7 @@ protected:
// we are it's still OK to load this URI. // we are it's still OK to load this URI.
PRBool IsOKToLoadURI(nsIURI* aURI); PRBool IsOKToLoadURI(nsIURI* aURI);
void ReattachEditorToWindow(nsIDOMWindow *aWindow, nsISHEntry *aSHEntry); void ReattachEditorToWindow(nsISHEntry *aSHEntry);
void DetachEditorFromWindow(nsISHEntry *aSHEntry); void DetachEditorFromWindow(nsISHEntry *aSHEntry);
protected: protected:
@ -677,10 +677,6 @@ protected:
static nsIURIFixup *sURIFixup; static nsIURIFixup *sURIFixup;
// Returns true when the currently open document has a detached editor
// waiting to be reattached.
PRBool HasDetachedEditor();
public: public:
class InterfaceRequestorProxy : public nsIInterfaceRequestor { class InterfaceRequestorProxy : public nsIInterfaceRequestor {
public: public:

View File

@ -73,12 +73,12 @@ nsDocShellEditorData::~nsDocShellEditorData()
void void
nsDocShellEditorData::TearDownEditor() nsDocShellEditorData::TearDownEditor()
{ {
NS_ASSERTION(mIsDetached, "We should be detached before tearing down");
if (mEditor) { if (mEditor) {
mEditor->PreDestroy(); mEditor->PreDestroy();
mEditor = nsnull; mEditor = nsnull;
} }
mEditingSession = nsnull; mEditingSession = nsnull;
mIsDetached = PR_FALSE;
} }
@ -244,12 +244,16 @@ nsDocShellEditorData::DetachFromWindow()
if (htmlDoc) if (htmlDoc)
mDetachedEditingState = htmlDoc->GetEditingState(); mDetachedEditingState = htmlDoc->GetEditingState();
mDocShell = nsnull;
return NS_OK; return NS_OK;
} }
nsresult nsresult
nsDocShellEditorData::ReattachToWindow(nsIDOMWindow *aWindow) nsDocShellEditorData::ReattachToWindow(nsIDocShell* aDocShell)
{ {
mDocShell = aDocShell;
nsCOMPtr<nsIDOMWindow> domWindow = do_GetInterface(mDocShell); nsCOMPtr<nsIDOMWindow> domWindow = do_GetInterface(mDocShell);
nsresult rv = mEditingSession->ReattachToWindow(domWindow); nsresult rv = mEditingSession->ReattachToWindow(domWindow);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);

View File

@ -72,7 +72,7 @@ public:
nsresult SetEditor(nsIEditor *inEditor); nsresult SetEditor(nsIEditor *inEditor);
void TearDownEditor(); void TearDownEditor();
nsresult DetachFromWindow(); nsresult DetachFromWindow();
nsresult ReattachToWindow(nsIDOMWindow *aWindow); nsresult ReattachToWindow(nsIDocShell *aDocShell);
protected: protected:

View File

@ -68,7 +68,7 @@ interface nsILayoutHistoryState;
interface nsISecureBrowserUI; interface nsISecureBrowserUI;
interface nsIDOMStorage; interface nsIDOMStorage;
[scriptable, uuid(4b00222a-8d0a-46d7-a1fe-43bd89d19324)] [scriptable, uuid(7d1cf6b9-daa3-476d-8f9f-9eb2a971a95c)]
interface nsIDocShell : nsISupports interface nsIDocShell : nsISupports
{ {
/** /**

View File

@ -58,7 +58,7 @@ class nsDocShellEditorData;
[ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData); [ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
[scriptable, uuid(abe54136-49e5-44ca-a749-290038c6b85d)] [scriptable, uuid(c16fde76-3108-450e-8c8c-ae8286f286ed)]
interface nsISHEntry : nsIHistoryEntry interface nsISHEntry : nsIHistoryEntry
{ {
/** URI for the document */ /** URI for the document */

View File

@ -50,6 +50,7 @@ _TEST_FILES = \
test_bug278916.html \ test_bug278916.html \
test_bug279495.html \ test_bug279495.html \
test_bug386782.html \ test_bug386782.html \
test_bug430624.html \
test_bug430723.html \ test_bug430723.html \
test_child.html \ test_child.html \
test_grandchild.html \ test_grandchild.html \

View File

@ -0,0 +1,55 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=430624
-->
<head>
<title>Test for Bug 430624</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=430624">Mozilla Bug 430624</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 430624 **/
function onLoad() {
window.frames[0].frameElement.onload = onReload;
window.frames[0].location = window.frames[0].location;
}
function onReload() {
var bodyElement = window.frames[0].frameElement.contentDocument.body;
sendChar('S', bodyElement);
sendChar('t', bodyElement);
sendChar('i', bodyElement);
sendChar('l', bodyElement);
sendChar('l', bodyElement);
sendChar(' ', bodyElement);
is(bodyElement.innerHTML, "Still contentEditable", "Check we're contentEditable after reload");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
<iframe onload="onLoad()" src="data:text/html;charset=utf-8,<body contenteditable>contentEditable</body>"></iframe>
</body>
</html>

View File

@ -0,0 +1,14 @@
<html>
<head>
<script>
function crash() {
window.frames[0].onload = null;
window.frames[0].location = 'data:text/html;charset=utf-8,2nd%20page';
}
</script>
</head>
<body onload="crash()">
<!-- iframe contents: <html><body onload="document.body.setAttribute('spellcheck', true);"></body></html> -->
<iframe src="data:text/html;charset=utf-8;base64,PGh0bWw%2BPGJvZHkgb25sb2FkPSJkb2N1bWVudC5ib2R5LnNldEF0dHJpYnV0ZSgnc3BlbGxjaGVjaycsIHRydWUpOyI%2BPC9ib2R5PjwvaHRtbD4%3D"></iframe>
</body>
</html>

View File

@ -1,3 +1,4 @@
load 382527-1.html load 382527-1.html
load 402172-1.html load 402172-1.html
load 407256-1.html load 407256-1.html
load 430624-1.html