From dad862ec1c44d9ae2a84b9bed28b08d9575306eb Mon Sep 17 00:00:00 2001 From: "bzbarsky%mit.edu" Date: Tue, 26 Apr 2005 03:31:29 +0000 Subject: [PATCH] Make text control state restoration work right even in subframes loaded from a different website. Bug 287446, r+sr=jst, a=chofmann git-svn-id: svn://10.0.0.236/trunk@172725 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/layout/forms/nsTextControlFrame.cpp | 81 +++++++++++++++++---- 1 file changed, 66 insertions(+), 15 deletions(-) diff --git a/mozilla/layout/forms/nsTextControlFrame.cpp b/mozilla/layout/forms/nsTextControlFrame.cpp index 703970b6496..3aba126bd94 100644 --- a/mozilla/layout/forms/nsTextControlFrame.cpp +++ b/mozilla/layout/forms/nsTextControlFrame.cpp @@ -124,6 +124,7 @@ #include "nsIDOMEventGroup.h" #include "nsIDOM3EventTarget.h" #include "nsINativeKeyBindings.h" +#include "nsIJSContextStack.h" #ifdef IBMBIDI #include "nsIBidiKeyboard.h" @@ -3003,6 +3004,7 @@ NS_IMETHODIMP nsTextControlFrame::GetValue(nsAString& aValue, PRBool aIgnoreWrap) { aValue.Truncate(); // initialize out param + nsresult rv = NS_OK; if (mEditor && mUseEditor) { @@ -3017,7 +3019,7 @@ nsTextControlFrame::GetValue(nsAString& aValue, PRBool aIgnoreWrap) if (!aIgnoreWrap) { nsFormControlHelper::nsHTMLTextWrap wrapProp; - nsresult rv = nsFormControlHelper::GetWrapPropertyEnum(mContent, wrapProp); + rv = nsFormControlHelper::GetWrapPropertyEnum(mContent, wrapProp); if (rv != NS_CONTENT_ATTR_NOT_THERE) { if (wrapProp == nsFormControlHelper::eHTMLTextWrap_Hard) { @@ -3026,7 +3028,30 @@ nsTextControlFrame::GetValue(nsAString& aValue, PRBool aIgnoreWrap) } } - mEditor->OutputToString(NS_LITERAL_STRING("text/plain"), flags, aValue); + // What follows is a bit of a hack. The problem is that we could be in + // this method because we're being destroyed for whatever reason while + // script is executing. If that happens, editor will run with the + // privileges of the executing script, which means it may not be able to + // access its own DOM nodes! Let's try to deal with that by pushing a null + // JSContext on the JSContext stack to make it clear that we're native + // code. Note that any script that's directly trying to access our value + // has to be going through some scriptable object to do that and that + // already does the relevant security checks. + // XXXbz if we could just get the textContent of our anonymous content (eg + // if plaintext editor didn't create
nodes all over), we wouldn't need + // this. + nsCOMPtr stack = + do_GetService("@mozilla.org/js/xpc/ContextStack;1"); + PRBool pushed = stack && NS_SUCCEEDED(stack->Push(nsnull)); + + rv = mEditor->OutputToString(NS_LITERAL_STRING("text/plain"), flags, + aValue); + + if (pushed) { + JSContext* cx; + stack->Pop(&cx); + NS_ASSERTION(!cx, "Unexpected JSContext popped!"); + } } else { @@ -3034,7 +3059,7 @@ nsTextControlFrame::GetValue(nsAString& aValue, PRBool aIgnoreWrap) nsCOMPtr inputControl = do_QueryInterface(mContent); if (inputControl) { - inputControl->GetValue(aValue); + rv = inputControl->GetValue(aValue); } else { @@ -3042,12 +3067,12 @@ nsTextControlFrame::GetValue(nsAString& aValue, PRBool aIgnoreWrap) = do_QueryInterface(mContent); if (textareaControl) { - textareaControl->GetValue(aValue); + rv = textareaControl->GetValue(aValue); } } } - return NS_OK; + return rv; } @@ -3056,6 +3081,8 @@ nsTextControlFrame::GetValue(nsAString& aValue, PRBool aIgnoreWrap) void nsTextControlFrame::SetValue(const nsAString& aValue) { + // XXX this method should actually propagate errors! It'd make debugging it + // so much easier... if (mEditor && mUseEditor) { nsAutoString currentValue; @@ -3067,15 +3094,6 @@ nsTextControlFrame::SetValue(const nsAString& aValue) // this is necessary to avoid infinite recursion if (!currentValue.Equals(aValue)) { - nsCOMPtr domSel; - nsCOMPtr selPriv; - mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel)); - if (domSel) - { - selPriv = do_QueryInterface(domSel); - if (selPriv) - selPriv->StartBatchChanges(); - } // \r is an illegal character in the dom, but people use them, // so convert windows and mac platform linebreaks to \n: // Unfortunately aValue is declared const, so we have to copy @@ -3087,9 +3105,34 @@ nsTextControlFrame::SetValue(const nsAString& aValue) nsresult rv = mEditor->GetDocument(getter_AddRefs(domDoc)); if (NS_FAILED(rv)) return; if (!domDoc) return; + + // Time to mess with our security context... See comments in GetValue() + // for why this is needed. Note that we have to do this up here, because + // otherwise SelectAll() will fail. + nsCOMPtr stack = + do_GetService("@mozilla.org/js/xpc/ContextStack;1"); + PRBool pushed = stack && NS_SUCCEEDED(stack->Push(nsnull)); + + nsCOMPtr domSel; + nsCOMPtr selPriv; + mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel)); + if (domSel) + { + selPriv = do_QueryInterface(domSel); + if (selPriv) + selPriv->StartBatchChanges(); + } + mSelCon->SelectAll(); nsCOMPtr htmlEditor = do_QueryInterface(mEditor); - if (!htmlEditor) return; + if (!htmlEditor) { + NS_WARNING("Somehow not a plaintext editor?"); + if (pushed) { + JSContext* cx; + stack->Pop(&cx); + NS_ASSERTION(!cx, "Unexpected JSContext popped!"); + } + } // Since this code does not handle user-generated changes to the text, // make sure we don't fire oninput when the editor notifies us. @@ -3110,6 +3153,7 @@ nsTextControlFrame::SetValue(const nsAString& aValue) flags &= ~(nsIPlaintextEditor::eEditorDisabledMask); flags &= ~(nsIPlaintextEditor::eEditorReadonlyMask); mEditor->SetFlags(flags); + if (currentValue.Length() < 1) mEditor->DeleteSelection(nsIEditor::eNone); else { @@ -3117,10 +3161,17 @@ nsTextControlFrame::SetValue(const nsAString& aValue) if (textEditor) textEditor->InsertText(currentValue); } + mEditor->SetFlags(savedFlags); if (selPriv) selPriv->EndBatchChanges(); + if (pushed) { + JSContext* cx; + stack->Pop(&cx); + NS_ASSERTION(!cx, "Unexpected JSContext popped!"); + } + if (outerTransaction) mNotifyOnInput = PR_TRUE; }