diff --git a/layout/forms/nsITextControlFrame.h b/layout/forms/nsITextControlFrame.h index 751a1e3d2082..223b7d898111 100644 --- a/layout/forms/nsITextControlFrame.h +++ b/layout/forms/nsITextControlFrame.h @@ -87,13 +87,6 @@ public: virtual nsFrameSelection* GetOwnedFrameSelection() = 0; virtual nsresult GetPhonetic(nsAString& aPhonetic) = 0; - - /** - * Ensure editor is initialized with the proper flags and the default value. - * @throws NS_ERROR_NOT_INITIALIZED if mEditor has not been created - * @throws various and sundry other things - */ - virtual nsresult EnsureEditorInitialized() = 0; }; #endif diff --git a/layout/forms/nsTextControlFrame.cpp b/layout/forms/nsTextControlFrame.cpp index 21365bbda264..477f3a29b54f 100644 --- a/layout/forms/nsTextControlFrame.cpp +++ b/layout/forms/nsTextControlFrame.cpp @@ -1306,6 +1306,38 @@ nsTextControlFrame::CalcIntrinsicSize(nsIRenderingContext* aRenderingContext, return NS_OK; } +void +nsTextControlFrame::DelayedEditorInit() +{ + nsIDocument* doc = mContent->GetCurrentDoc(); + if (!doc) { + return; + } + + nsWeakFrame weakFrame(this); + + // Flush out content on our document. Have to do this, because script + // blockers don't prevent the sink flushing out content and notifying in the + // process, which can destroy frames. + doc->FlushPendingNotifications(Flush_ContentAndNotify); + if (!weakFrame.IsAlive()) { + return; + } + + // Make sure that editor init doesn't do things that would kill us off + // (especially off the script blockers it'll create for its DOM mutations). + nsAutoScriptBlocker scriptBlocker; + + // Time to mess with our security context... See comments in GetValue() + // for why this is needed. + nsCxPusher pusher; + pusher.PushNull(); + + InitEditor(); + if (IsFocusedContent(GetContent())) + SetFocus(PR_TRUE, PR_FALSE); +} + PRInt32 nsTextControlFrame::GetWrapCols() { @@ -1327,58 +1359,23 @@ nsTextControlFrame::GetWrapCols() } nsresult -nsTextControlFrame::EnsureEditorInitialized() +nsTextControlFrame::InitEditor() { // This method initializes our editor, if needed. - + // This code used to be called from CreateAnonymousContent(), but // when the editor set the initial string, it would trigger a // PresShell listener which called FlushPendingNotifications() // during frame construction. This was causing other form controls - // to display wrong values. Additionally, calling this every time - // a text frame control is instantiated means that we're effectively - // instantiating the editor for all text fields, even if they - // never get used. + // to display wrong values. So we call this from a script runner + // now. // Check if this method has been called already. // If so, just return early. + if (mUseEditor) return NS_OK; - nsIDocument* doc = mContent->GetCurrentDoc(); - NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); - - nsWeakFrame weakFrame(this); - - // Flush out content on our document. Have to do this, because script - // blockers don't prevent the sink flushing out content and notifying in the - // process, which can destroy frames. - doc->FlushPendingNotifications(Flush_ContentAndNotify); - NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_ERROR_FAILURE); - - // Make sure that editor init doesn't do things that would kill us off - // (especially off the script blockers it'll create for its DOM mutations). - nsAutoScriptBlocker scriptBlocker; - - // Time to mess with our security context... See comments in GetValue() - // for why this is needed. - nsCxPusher pusher; - pusher.PushNull(); - - // Make sure that we try to focus the content even if the method fails - class EnsureSetFocus { - public: - explicit EnsureSetFocus(nsTextControlFrame* aFrame) - : mFrame(aFrame) {} - ~EnsureSetFocus() { - if (IsFocusedContent(mFrame->GetContent())) - mFrame->SetFocus(PR_TRUE, PR_FALSE); - } - private: - nsTextControlFrame *mFrame; - }; - EnsureSetFocus makeSureSetFocusHappens(this); - // Create an editor nsresult rv; @@ -1509,38 +1506,43 @@ nsTextControlFrame::EnsureEditorInitialized() // editor. mUseEditor = PR_TRUE; - // Set the editor's contents to our default value. We have to be - // sure to use the editor so that '*' characters get displayed for - // password fields, etc. SetValue() will call the editor for us. We - // want to call this even if defaultValue is empty, since empty text - // inputs have a single non-breaking space in the textnode under - // mAnonymousDiv, and this space needs to go away as we init the - // editor. + // If we have a default value, insert it under the div we created + // above, but be sure to use the editor so that '*' characters get + // displayed for password fields, etc. SetValue() will call the + // editor for us. - // Avoid causing reentrant painting and reflowing by telling the editor - // that we don't want it to force immediate view refreshes or force - // immediate reflows during any editor calls. + if (!defaultValue.IsEmpty()) { + // Avoid causing reentrant painting and reflowing by telling the editor + // that we don't want it to force immediate view refreshes or force + // immediate reflows during any editor calls. - rv = mEditor->SetFlags(editorFlags | - nsIPlaintextEditor::eEditorUseAsyncUpdatesMask); - NS_ENSURE_SUCCESS(rv, rv); + rv = mEditor->SetFlags(editorFlags | + nsIPlaintextEditor::eEditorUseAsyncUpdatesMask); - // Now call SetValue() which will make the necessary editor calls to set - // the default value. Make sure to turn off undo before setting the default - // value, and turn it back on afterwards. This will make sure we can't undo - // past the default value. + if (NS_FAILED(rv)) + return rv; - rv = mEditor->EnableUndo(PR_FALSE); - NS_ENSURE_SUCCESS(rv, rv); + // Now call SetValue() which will make the necessary editor calls to set + // the default value. Make sure to turn off undo before setting the default + // value, and turn it back on afterwards. This will make sure we can't undo + // past the default value. - SetValue(defaultValue); + rv = mEditor->EnableUndo(PR_FALSE); - rv = mEditor->EnableUndo(PR_TRUE); - NS_ASSERTION(NS_SUCCEEDED(rv),"Transaction Manager must have failed"); + if (NS_FAILED(rv)) + return rv; - // Now restore the original editor flags. - rv = mEditor->SetFlags(editorFlags); - NS_ENSURE_SUCCESS(rv, rv); + SetValue(defaultValue); + + rv = mEditor->EnableUndo(PR_TRUE); + NS_ASSERTION(NS_SUCCEEDED(rv),"Transaction Manager must have failed"); + + // Now restore the original editor flags. + rv = mEditor->SetFlags(editorFlags); + + if (NS_FAILED(rv)) + return rv; + } nsCOMPtr transMgr; mEditor->GetTransactionManager(getter_AddRefs(transMgr)); @@ -1570,7 +1572,7 @@ nsTextControlFrame::CreateAnonymousContent(nsTArray& aElements) { mState |= NS_FRAME_INDEPENDENT_SELECTION; - nsIPresShell *shell = PresContext()->GetPresShell(); + nsIPresShell* shell = PresContext()->GetPresShell(); if (!shell) return NS_ERROR_FAILURE; @@ -2382,7 +2384,7 @@ nsTextControlFrame::AttributeChanged(PRInt32 aNameSpaceID, if (!(flags & nsIPlaintextEditor::eEditorDisabledMask) && IsFocusedContent(mContent)) mSelCon->SetCaretEnabled(PR_TRUE); - } + } mEditor->SetFlags(flags); } else if (nsGkAtoms::disabled == aAttribute) diff --git a/layout/forms/nsTextControlFrame.h b/layout/forms/nsTextControlFrame.h index 1c97972a1013..7b6d5316eaf4 100644 --- a/layout/forms/nsTextControlFrame.h +++ b/layout/forms/nsTextControlFrame.h @@ -175,13 +175,6 @@ public: nsresult GetPhonetic(nsAString& aPhonetic); - /** - * Ensure mEditor is initialized with the proper flags and the default value. - * @throws NS_ERROR_NOT_INITIALIZED if mEditor has not been created - * @throws various and sundry other things - */ - virtual nsresult EnsureEditorInitialized(); - //==== END NSITEXTCONTROLFRAME //==== OVERLOAD of nsIFrame virtual nsIAtom* GetType() const; @@ -255,7 +248,7 @@ protected: mWeakFrame.GetFrame()->PresContext()->GetPresShell(); PRBool observes = shell->ObservesNativeAnonMutationsForPrint(); shell->ObserveNativeAnonMutationsForPrint(PR_TRUE); - mFrame->EnsureEditorInitialized(); + mFrame->DelayedEditorInit(); shell->ObserveNativeAnonMutationsForPrint(observes); } return NS_OK; @@ -266,6 +259,10 @@ protected: nsTextControlFrame* mFrame; }; + // Init our editor and then make sure to focus our text input + // listener if our content node has focus. + void DelayedEditorInit(); + nsresult DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset, PRInt32 *aResult); nsresult OffsetToDOMPoint(PRInt32 aOffset, nsIDOMNode** aResult, PRInt32* aPosition); @@ -275,6 +272,12 @@ protected: * @return whether this control is scrollable */ PRBool IsScrollable() const; + /** + * Initialize mEditor with the proper flags and the default value. + * @throws NS_ERROR_NOT_INITIALIZED if mEditor has not been created + * @throws various and sundry other things + */ + nsresult InitEditor(); /** * Strip all \n, \r and nulls from the given string * @param aString the string to remove newlines from [in/out]