Bug 542919 - Refactor the plain text editor initialization to facilitate lazy initialization; r=bzbarsky sr=roc

--HG--
extra : rebase_source : 5c6baa16c4f3c91f8564cfdf394d70c8ea507861
This commit is contained in:
Ehsan Akhgari 2010-02-01 23:00:06 -05:00
parent c47d8c7d26
commit c83636a241
3 changed files with 82 additions and 80 deletions

View File

@ -87,6 +87,13 @@ 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

View File

@ -1306,38 +1306,6 @@ 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()
{
@ -1359,23 +1327,58 @@ nsTextControlFrame::GetWrapCols()
}
nsresult
nsTextControlFrame::InitEditor()
nsTextControlFrame::EnsureEditorInitialized()
{
// 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. So we call this from a script runner
// now.
// 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.
// 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;
@ -1506,43 +1509,38 @@ nsTextControlFrame::InitEditor()
// editor.
mUseEditor = PR_TRUE;
// 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.
// 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 (!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.
// 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);
rv = mEditor->SetFlags(editorFlags |
nsIPlaintextEditor::eEditorUseAsyncUpdatesMask);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv))
return 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.
// 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.
rv = mEditor->EnableUndo(PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
rv = mEditor->EnableUndo(PR_FALSE);
SetValue(defaultValue);
if (NS_FAILED(rv))
return rv;
rv = mEditor->EnableUndo(PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv),"Transaction Manager must have failed");
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;
}
// Now restore the original editor flags.
rv = mEditor->SetFlags(editorFlags);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsITransactionManager> transMgr;
mEditor->GetTransactionManager(getter_AddRefs(transMgr));
@ -1572,7 +1570,7 @@ nsTextControlFrame::CreateAnonymousContent(nsTArray<nsIContent*>& aElements)
{
mState |= NS_FRAME_INDEPENDENT_SELECTION;
nsIPresShell* shell = PresContext()->GetPresShell();
nsIPresShell *shell = PresContext()->GetPresShell();
if (!shell)
return NS_ERROR_FAILURE;
@ -2384,7 +2382,7 @@ nsTextControlFrame::AttributeChanged(PRInt32 aNameSpaceID,
if (!(flags & nsIPlaintextEditor::eEditorDisabledMask) &&
IsFocusedContent(mContent))
mSelCon->SetCaretEnabled(PR_TRUE);
}
}
mEditor->SetFlags(flags);
}
else if (nsGkAtoms::disabled == aAttribute)

View File

@ -175,6 +175,13 @@ 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;
@ -248,7 +255,7 @@ protected:
mWeakFrame.GetFrame()->PresContext()->GetPresShell();
PRBool observes = shell->ObservesNativeAnonMutationsForPrint();
shell->ObserveNativeAnonMutationsForPrint(PR_TRUE);
mFrame->DelayedEditorInit();
mFrame->EnsureEditorInitialized();
shell->ObserveNativeAnonMutationsForPrint(observes);
}
return NS_OK;
@ -259,10 +266,6 @@ 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);
@ -272,12 +275,6 @@ 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]