Bug 221820 - Part 2: Make the editor initialization lazy (initialize only when needed); r=bzbarsky
This commit is contained in:
@@ -1128,9 +1128,8 @@ nsHTMLInputElement::SetValueInternal(const nsAString& aValue,
|
|||||||
// value yet (per OwnsValue()), it will turn around and call
|
// value yet (per OwnsValue()), it will turn around and call
|
||||||
// TakeTextFrameValue() on us, but will update its display with the new
|
// TakeTextFrameValue() on us, but will update its display with the new
|
||||||
// value if needed.
|
// value if needed.
|
||||||
formControlFrame->SetFormProperty(
|
return formControlFrame->SetFormProperty(
|
||||||
aUserInput ? nsGkAtoms::userInput : nsGkAtoms::value, aValue);
|
aUserInput ? nsGkAtoms::userInput : nsGkAtoms::value, aValue);
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetValueChanged(PR_TRUE);
|
SetValueChanged(PR_TRUE);
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ LOCAL_INCLUDES = \
|
|||||||
-I$(srcdir)/../xul/base/src \
|
-I$(srcdir)/../xul/base/src \
|
||||||
-I$(srcdir)/../../content/base/src \
|
-I$(srcdir)/../../content/base/src \
|
||||||
-I$(srcdir)/../../content/html/content/src \
|
-I$(srcdir)/../../content/html/content/src \
|
||||||
|
-I$(srcdir)/../../editor/libeditor/base \
|
||||||
|
-I$(srcdir)/../../editor/libeditor/text \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
DEFINES += -D_IMPL_NS_LAYOUT
|
DEFINES += -D_IMPL_NS_LAYOUT
|
||||||
|
|||||||
@@ -118,6 +118,7 @@
|
|||||||
#include "nsINativeKeyBindings.h"
|
#include "nsINativeKeyBindings.h"
|
||||||
#include "nsIJSContextStack.h"
|
#include "nsIJSContextStack.h"
|
||||||
#include "nsFocusManager.h"
|
#include "nsFocusManager.h"
|
||||||
|
#include "nsTextEditRules.h"
|
||||||
|
|
||||||
#define DEFAULT_COLUMN_WIDTH 20
|
#define DEFAULT_COLUMN_WIDTH 20
|
||||||
|
|
||||||
@@ -1331,7 +1332,8 @@ nsTextControlFrame::EnsureEditorInitialized()
|
|||||||
// to display wrong values. Additionally, calling this every time
|
// to display wrong values. Additionally, calling this every time
|
||||||
// a text frame control is instantiated means that we're effectively
|
// a text frame control is instantiated means that we're effectively
|
||||||
// instantiating the editor for all text fields, even if they
|
// 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.
|
// Check if this method has been called already.
|
||||||
// If so, just return early.
|
// If so, just return early.
|
||||||
@@ -1412,6 +1414,9 @@ nsTextControlFrame::EnsureEditorInitialized()
|
|||||||
if (!domdoc)
|
if (!domdoc)
|
||||||
return NS_ERROR_FAILURE;
|
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);
|
rv = mEditor->Init(domdoc, shell, mValueDiv, mSelCon, editorFlags);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
@@ -1622,6 +1627,9 @@ nsTextControlFrame::CreateAnonymousContent(nsTArray<nsIContent*>& aElements)
|
|||||||
if (!aElements.AppendElement(mValueDiv))
|
if (!aElements.AppendElement(mValueDiv))
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
rv = UpdateValueDisplay(PR_FALSE);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// Create selection
|
// Create selection
|
||||||
|
|
||||||
mFrameSel = do_CreateInstance(kFrameSelectionCID, &rv);
|
mFrameSel = do_CreateInstance(kFrameSelectionCID, &rv);
|
||||||
@@ -1662,11 +1670,14 @@ nsTextControlFrame::CreateAnonymousContent(nsTArray<nsIContent*>& aElements)
|
|||||||
(mTextListener));
|
(mTextListener));
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
|
if (!IsSingleLineTextControl()) {
|
||||||
"Someone forgot a script blocker?");
|
// textareas are eagerly initialized
|
||||||
|
NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
|
||||||
|
"Someone forgot a script blocker?");
|
||||||
|
|
||||||
if (!nsContentUtils::AddScriptRunner(new EditorInitializer(this))) {
|
if (!nsContentUtils::AddScriptRunner(new EditorInitializer(this))) {
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now create the placeholder anonymous content
|
// Now create the placeholder anonymous content
|
||||||
@@ -2459,7 +2470,7 @@ nsTextControlFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|||||||
{ // unset disabled
|
{ // unset disabled
|
||||||
flags &= ~(nsIPlaintextEditor::eEditorDisabledMask);
|
flags &= ~(nsIPlaintextEditor::eEditorDisabledMask);
|
||||||
mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);
|
mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);
|
||||||
}
|
}
|
||||||
mEditor->SetFlags(flags);
|
mEditor->SetFlags(flags);
|
||||||
}
|
}
|
||||||
else if (nsGkAtoms::placeholder == aAttribute)
|
else if (nsGkAtoms::placeholder == aAttribute)
|
||||||
@@ -2468,6 +2479,9 @@ nsTextControlFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|||||||
UpdatePlaceholderText(PR_TRUE);
|
UpdatePlaceholderText(PR_TRUE);
|
||||||
NS_ENSURE_STATE(weakFrame.IsAlive());
|
NS_ENSURE_STATE(weakFrame.IsAlive());
|
||||||
}
|
}
|
||||||
|
else if (!mUseEditor && nsGkAtoms::value == aAttribute) {
|
||||||
|
UpdateValueDisplay(PR_TRUE);
|
||||||
|
}
|
||||||
// Allow the base class to handle common attributes supported
|
// Allow the base class to handle common attributes supported
|
||||||
// by all form elements...
|
// by all form elements...
|
||||||
else {
|
else {
|
||||||
@@ -2812,6 +2826,12 @@ nsTextControlFrame::SetValue(const nsAString& aValue)
|
|||||||
{
|
{
|
||||||
textControl->TakeTextFrameValue(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;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@@ -2878,6 +2898,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
|
/* static */ void
|
||||||
nsTextControlFrame::ShutDown()
|
nsTextControlFrame::ShutDown()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -275,17 +275,29 @@ protected:
|
|||||||
* @return whether this control is scrollable
|
* @return whether this control is scrollable
|
||||||
*/
|
*/
|
||||||
PRBool IsScrollable() const;
|
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
|
* Strip all \n, \r and nulls from the given string
|
||||||
* @param aString the string to remove newlines from [in/out]
|
* @param aString the string to remove newlines from [in/out]
|
||||||
*/
|
*/
|
||||||
void RemoveNewlines(nsString &aString);
|
void RemoveNewlines(nsString &aString);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the maxlength attribute
|
* Get the maxlength attribute
|
||||||
* @param aMaxLength the value of the max length attr
|
* @param aMaxLength the value of the max length attr
|
||||||
* @returns PR_FALSE if attr not defined
|
* @returns PR_FALSE if attr not defined
|
||||||
*/
|
*/
|
||||||
PRBool GetMaxLength(PRInt32* aMaxLength);
|
PRBool GetMaxLength(PRInt32* aMaxLength);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find out whether an attribute exists on the content or not.
|
* Find out whether an attribute exists on the content or not.
|
||||||
* @param aAtt the attribute to determine the existence of
|
* @param aAtt the attribute to determine the existence of
|
||||||
@@ -299,9 +311,6 @@ protected:
|
|||||||
* @param aPresContext the current pres context
|
* @param aPresContext the current pres context
|
||||||
*/
|
*/
|
||||||
void PreDestroy();
|
void PreDestroy();
|
||||||
/**
|
|
||||||
* Fire the onChange event.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Helper methods
|
// Helper methods
|
||||||
/**
|
/**
|
||||||
@@ -309,10 +318,12 @@ protected:
|
|||||||
* @return the number of columns to use
|
* @return the number of columns to use
|
||||||
*/
|
*/
|
||||||
PRInt32 GetCols();
|
PRInt32 GetCols();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the column index to wrap at, or -1 if we shouldn't wrap
|
* Get the column index to wrap at, or -1 if we shouldn't wrap
|
||||||
*/
|
*/
|
||||||
PRInt32 GetWrapCols();
|
PRInt32 GetWrapCols();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the rows attribute (if textarea) or a default
|
* Get the rows attribute (if textarea) or a default
|
||||||
* @return the number of rows to use
|
* @return the number of rows to use
|
||||||
|
|||||||
Reference in New Issue
Block a user