Bug 221820 - Part 2: Make the editor initialization lazy (initialize only when needed); r=bzbarsky

--HG--
extra : rebase_source : bf84341934b14c78fadc162607721e9325673fc4
This commit is contained in:
Ehsan Akhgari 2010-02-02 10:49:55 -05:00
Родитель 64a3144e62
Коммит a5e3d44e9b
4 изменённых файлов: 140 добавлений и 11 удалений

Просмотреть файл

@ -1128,9 +1128,8 @@ nsHTMLInputElement::SetValueInternal(const nsAString& aValue,
// value yet (per OwnsValue()), it will turn around and call
// TakeTextFrameValue() on us, but will update its display with the new
// value if needed.
formControlFrame->SetFormProperty(
return formControlFrame->SetFormProperty(
aUserInput ? nsGkAtoms::userInput : nsGkAtoms::value, aValue);
return NS_OK;
}
SetValueChanged(PR_TRUE);

Просмотреть файл

@ -91,6 +91,8 @@ LOCAL_INCLUDES = \
-I$(srcdir)/../xul/base/src \
-I$(srcdir)/../../content/base/src \
-I$(srcdir)/../../content/html/content/src \
-I$(srcdir)/../../editor/libeditor/base \
-I$(srcdir)/../../editor/libeditor/text \
$(NULL)
DEFINES += -D_IMPL_NS_LAYOUT

Просмотреть файл

@ -118,6 +118,7 @@
#include "nsINativeKeyBindings.h"
#include "nsIJSContextStack.h"
#include "nsFocusManager.h"
#include "nsTextEditRules.h"
#define DEFAULT_COLUMN_WIDTH 20
@ -1331,7 +1332,8 @@ nsTextControlFrame::EnsureEditorInitialized()
// 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.
// never get used. So, now this method is being called lazily only
// when we actually need an editor.
// Check if this method has been called already.
// If so, just return early.
@ -1412,6 +1414,9 @@ nsTextControlFrame::EnsureEditorInitialized()
if (!domdoc)
return NS_ERROR_FAILURE;
// Make sure we clear out the non-breaking space before we initialize the editor
UpdateValueDisplay(PR_FALSE, PR_TRUE);
rv = mEditor->Init(domdoc, shell, mValueDiv, mSelCon, editorFlags);
NS_ENSURE_SUCCESS(rv, rv);
@ -1619,6 +1624,9 @@ nsTextControlFrame::CreateAnonymousContent(nsTArray<nsIContent*>& aElements)
if (!aElements.AppendElement(mValueDiv))
return NS_ERROR_OUT_OF_MEMORY;
rv = UpdateValueDisplay(PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
// Create selection
mFrameSel = do_CreateInstance(kFrameSelectionCID, &rv);
@ -1659,11 +1667,14 @@ nsTextControlFrame::CreateAnonymousContent(nsTArray<nsIContent*>& aElements)
(mTextListener));
}
NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
"Someone forgot a script blocker?");
if (!IsSingleLineTextControl()) {
// textareas are eagerly initialized
NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
"Someone forgot a script blocker?");
if (!nsContentUtils::AddScriptRunner(new EditorInitializer(this))) {
return NS_ERROR_OUT_OF_MEMORY;
if (!nsContentUtils::AddScriptRunner(new EditorInitializer(this))) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
// Now create the placeholder anonymous content
@ -2456,7 +2467,7 @@ nsTextControlFrame::AttributeChanged(PRInt32 aNameSpaceID,
{ // unset disabled
flags &= ~(nsIPlaintextEditor::eEditorDisabledMask);
mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);
}
}
mEditor->SetFlags(flags);
}
else if (nsGkAtoms::placeholder == aAttribute)
@ -2465,6 +2476,9 @@ nsTextControlFrame::AttributeChanged(PRInt32 aNameSpaceID,
UpdatePlaceholderText(PR_TRUE);
NS_ENSURE_STATE(weakFrame.IsAlive());
}
else if (!mUseEditor && nsGkAtoms::value == aAttribute) {
UpdateValueDisplay(PR_TRUE);
}
// Allow the base class to handle common attributes supported
// by all form elements...
else {
@ -2809,6 +2823,12 @@ nsTextControlFrame::SetValue(const nsAString& aValue)
{
textControl->TakeTextFrameValue(aValue);
}
// The only time mEditor is non-null but mUseEditor is false is when the
// frame is being torn down. If that's what's going on, don't bother with
// updating the display.
if (!mEditor) {
UpdateValueDisplay(PR_TRUE, PR_FALSE, &aValue);
}
}
return NS_OK;
}
@ -2875,6 +2895,103 @@ nsTextControlFrame::SetValueChanged(PRBool aValueChanged)
}
}
nsresult
nsTextControlFrame::UpdateValueDisplay(PRBool aNotify,
PRBool aBeforeEditorInit,
const nsAString *aValue)
{
if (!IsSingleLineTextControl()) // textareas don't use this
return NS_OK;
NS_PRECONDITION(mValueDiv, "Must have a div content\n");
NS_PRECONDITION(!mUseEditor,
"Do not call this after editor has been initialized");
NS_ASSERTION(mValueDiv->GetChildCount() <= 1,
"Cannot have more than one child node");
enum {
NO_NODE,
TXT_NODE,
BR_NODE
} childNodeType = NO_NODE;
nsIContent* childNode = mValueDiv->GetChildAt(0);
#ifdef NS_DEBUG
if (aBeforeEditorInit)
NS_ASSERTION(childNode, "A child node should exist before initializing the editor");
#endif
if (childNode) {
if (childNode->IsNodeOfType(nsINode::eELEMENT))
childNodeType = BR_NODE;
else if (childNode->IsNodeOfType(nsINode::eTEXT))
childNodeType = TXT_NODE;
#ifdef NS_DEBUG
else
NS_NOTREACHED("Invalid child node found");
#endif
}
// Get the current value of the textfield from the content.
nsAutoString value;
if (aValue) {
value = *aValue;
} else {
GetValue(value, PR_TRUE);
}
if (aBeforeEditorInit && value.IsEmpty()) {
mValueDiv->RemoveChildAt(0, PR_TRUE, PR_FALSE);
return NS_OK;
}
nsTextEditRules::HandleNewLines(value, -1);
nsresult rv;
if (value.IsEmpty()) {
if (childNodeType != BR_NODE) {
nsCOMPtr<nsINodeInfo> nodeInfo;
nodeInfo = mContent->NodeInfo()
->NodeInfoManager()
->GetNodeInfo(nsGkAtoms::br, nsnull,
kNameSpaceID_XHTML);
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<nsIContent> brNode;
rv = NS_NewHTMLElement(getter_AddRefs(brNode), nodeInfo, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMElement> brElement = do_QueryInterface(brNode);
NS_ENSURE_TRUE(brElement, NS_ERROR_UNEXPECTED);
brElement->SetAttribute(kMOZEditorBogusNodeAttr, kMOZEditorBogusNodeValue);
mValueDiv->RemoveChildAt(0, aNotify, PR_FALSE);
mValueDiv->AppendChildTo(brNode, aNotify);
}
} else {
if (IsPasswordTextControl())
nsTextEditRules::FillBufWithPWChars(&value, value.Length());
// Set up a textnode with our value
nsCOMPtr<nsIContent> textNode;
if (childNodeType != TXT_NODE) {
rv = NS_NewTextNode(getter_AddRefs(textNode),
mContent->NodeInfo()->NodeInfoManager());
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(textNode, "Must have textcontent!\n");
mValueDiv->RemoveChildAt(0, aNotify, PR_FALSE);
mValueDiv->AppendChildTo(textNode, aNotify);
} else {
textNode = childNode;
}
textNode->SetText(value, aNotify);
}
return NS_OK;
}
/* static */ void
nsTextControlFrame::ShutDown()
{

Просмотреть файл

@ -275,17 +275,29 @@ protected:
* @return whether this control is scrollable
*/
PRBool IsScrollable() const;
/**
* Update the textnode under our anonymous div to show the new
* value. This should only be called when we have no editor yet.
* @throws NS_ERROR_UNEXPECTED if the div has no text content
*/
nsresult UpdateValueDisplay(PRBool aNotify,
PRBool aBeforeEditorInit = PR_FALSE,
const nsAString *aValue = nsnull);
/**
* Strip all \n, \r and nulls from the given string
* @param aString the string to remove newlines from [in/out]
*/
void RemoveNewlines(nsString &aString);
/**
* Get the maxlength attribute
* @param aMaxLength the value of the max length attr
* @returns PR_FALSE if attr not defined
*/
PRBool GetMaxLength(PRInt32* aMaxLength);
/**
* Find out whether an attribute exists on the content or not.
* @param aAtt the attribute to determine the existence of
@ -299,9 +311,6 @@ protected:
* @param aPresContext the current pres context
*/
void PreDestroy();
/**
* Fire the onChange event.
*/
// Helper methods
/**
@ -309,10 +318,12 @@ protected:
* @return the number of columns to use
*/
PRInt32 GetCols();
/**
* Get the column index to wrap at, or -1 if we shouldn't wrap
*/
PRInt32 GetWrapCols();
/**
* Get the rows attribute (if textarea) or a default
* @return the number of rows to use