Fix for bug 30091. nsFormControlList::NamedItem() was doing a linear walk through the form control list. Now it uses a hash table lookup. This greatly reduces the time for the screen to update when one clicks on the Program list box on the Bugzilla query page.

This commit is contained in:
nisheeth%netscape.com 2000-04-19 07:49:07 +00:00
Родитель e731b49281
Коммит d6a5b5bf19
24 изменённых файлов: 468 добавлений и 88 удалений

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

@ -23,6 +23,7 @@
#define nsIForm_h___ #define nsIForm_h___
#include "nsISupports.h" #include "nsISupports.h"
#include "nsString.h"
class nsIFormControl; class nsIFormControl;
class nsISizeOfHandler; class nsISizeOfHandler;
@ -51,6 +52,15 @@ public:
*/ */
NS_IMETHOD AddElement(nsIFormControl* aElement) = 0; NS_IMETHOD AddElement(nsIFormControl* aElement) = 0;
/**
* Add an element to the lookup table mainted by the form.
* We can't fold this method into AddElement() because when
* AddElement() is called, the form control has no
* attributes. The name or id attributes of the form control
* are used as a key into the table.
*/
NS_IMETHOD AddElementToTable(nsIFormControl* aElement, const nsString& aName) = 0;
/** /**
* Get the element at a specified index position * Get the element at a specified index position
* @param aIndex the index * @param aIndex the index

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

@ -3121,3 +3121,69 @@ nsGenericHTMLContainerElement::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
return NS_OK; return NS_OK;
} }
//----------------------------------------------------------------------
nsGenericHTMLContainerFormElement::nsGenericHTMLContainerFormElement()
{
mForm = nsnull;
}
nsGenericHTMLContainerFormElement::~nsGenericHTMLContainerFormElement()
{
// Do nothing
}
nsresult
nsGenericHTMLContainerFormElement::SetForm(nsIForm* aForm)
{
mForm = aForm;
return NS_OK;
}
nsresult
nsGenericHTMLContainerFormElement::SetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName, const nsString& aValue,
PRBool aNotify)
{
// Add the control to the hash table
nsCOMPtr<nsIFormControl> control;
control = do_QueryInterface(mContent);
if (mForm && (nsHTMLAtoms::name == aName || nsHTMLAtoms::id == aName))
mForm->AddElementToTable(control, aValue);
return nsGenericHTMLElement::SetAttribute(aNameSpaceID, aName, aValue, aNotify);
}
//----------------------------------------------------------------------
nsGenericHTMLLeafFormElement::nsGenericHTMLLeafFormElement()
{
mForm = nsnull;
}
nsGenericHTMLLeafFormElement::~nsGenericHTMLLeafFormElement()
{
// Do nothing
}
nsresult
nsGenericHTMLLeafFormElement::SetForm(nsIForm* aForm)
{
mForm = aForm;
return NS_OK;
}
nsresult
nsGenericHTMLLeafFormElement::SetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName, const nsString& aValue,
PRBool aNotify)
{
// Add the control to the hash table
nsCOMPtr<nsIFormControl> control;
control = do_QueryInterface(mContent);
if (mForm && (nsHTMLAtoms::name == aName || nsHTMLAtoms::id == aName))
mForm->AddElementToTable(control, aValue);
return nsGenericHTMLElement::SetAttribute(aNameSpaceID, aName, aValue, aNotify);
}
//----------------------------------------------------------------------

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

@ -454,6 +454,42 @@ public:
//---------------------------------------------------------------------- //----------------------------------------------------------------------
class nsGenericHTMLContainerFormElement : public nsGenericHTMLContainerElement {
public:
nsGenericHTMLContainerFormElement();
~nsGenericHTMLContainerFormElement();
nsresult SetForm(nsIForm* aForm);
nsresult SetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName, const nsString& aValue,
PRBool aNotify);
nsresult SetAttribute(const nsString& aName, const nsString& aValue)
{
return nsGenericHTMLElement::SetAttribute(aName, aValue);
}
nsIForm* mForm;
};
//----------------------------------------------------------------------
class nsGenericHTMLLeafFormElement : public nsGenericHTMLLeafElement {
public:
nsGenericHTMLLeafFormElement();
~nsGenericHTMLLeafFormElement();
nsresult SetForm(nsIForm* aForm);
nsresult SetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName, const nsString& aValue,
PRBool aNotify);
nsresult SetAttribute(const nsString& aName, const nsString& aValue)
{
return nsGenericHTMLElement::SetAttribute(aName, aValue);
}
nsIForm* mForm;
};
//----------------------------------------------------------------------
/** /**
* Implement the nsIDOMHTMLElement API by forwarding the methods to a * Implement the nsIDOMHTMLElement API by forwarding the methods to a
* generic content object (either nsGenericHTMLLeafElement or * generic content object (either nsGenericHTMLLeafElement or

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

@ -97,7 +97,7 @@ public:
NS_IMETHOD Init() { return NS_OK; } NS_IMETHOD Init() { return NS_OK; }
protected: protected:
nsGenericHTMLContainerElement mInner; nsGenericHTMLContainerFormElement mInner;
nsIForm* mForm; nsIForm* mForm;
PRInt32 mType; PRInt32 mType;
}; };
@ -528,6 +528,9 @@ nsHTMLButtonElement::SetForm(nsIDOMHTMLFormElement* aForm)
} }
} }
NS_IF_RELEASE(formControl); NS_IF_RELEASE(formControl);
mInner.SetForm(mForm);
return result; return result;
} }

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

@ -79,7 +79,7 @@ public:
NS_IMETHOD Init() { return NS_OK; } NS_IMETHOD Init() { return NS_OK; }
protected: protected:
nsGenericHTMLContainerElement mInner; nsGenericHTMLContainerFormElement mInner;
nsIForm* mForm; nsIForm* mForm;
}; };
@ -224,6 +224,9 @@ nsHTMLFieldSetElement::SetForm(nsIDOMHTMLFormElement* aForm)
} }
} }
NS_IF_RELEASE(formControl); NS_IF_RELEASE(formControl);
mInner.SetForm(mForm);
return result; return result;
} }

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

@ -44,6 +44,9 @@
#include "nsIScriptGlobalObject.h" #include "nsIScriptGlobalObject.h"
#include "nsDOMError.h" #include "nsDOMError.h"
#include "nsLayoutUtils.h" #include "nsLayoutUtils.h"
#include "nsHashTable.h"
static const int NS_FORM_CONTROL_LIST_HASHTABLE_SIZE = 64;
static NS_DEFINE_IID(kIDOMHTMLFormElementIID, NS_IDOMHTMLFORMELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLFormElementIID, NS_IDOMHTMLFORMELEMENT_IID);
static NS_DEFINE_IID(kIFormControlIID, NS_IFORMCONTROL_IID); static NS_DEFINE_IID(kIFormControlIID, NS_IFORMCONTROL_IID);
@ -109,6 +112,7 @@ public:
// nsIForm // nsIForm
NS_IMETHOD AddElement(nsIFormControl* aElement); NS_IMETHOD AddElement(nsIFormControl* aElement);
NS_IMETHOD AddElementToTable(nsIFormControl* aChild, const nsString& aName);
NS_IMETHOD GetElementAt(PRInt32 aIndex, nsIFormControl** aElement) const; NS_IMETHOD GetElementAt(PRInt32 aIndex, nsIFormControl** aElement) const;
NS_IMETHOD GetElementCount(PRUint32* aCount) const; NS_IMETHOD GetElementCount(PRUint32* aCount) const;
NS_IMETHOD RemoveElement(nsIFormControl* aElement, PRBool aChildIsRef = PR_TRUE); NS_IMETHOD RemoveElement(nsIFormControl* aElement, PRBool aChildIsRef = PR_TRUE);
@ -138,6 +142,10 @@ public:
NS_DECL_IDOMHTMLFORMCONTROLLIST NS_DECL_IDOMHTMLFORMCONTROLLIST
nsresult GetNamedObject(JSContext* aContext, jsval aID, JSObject** aObj); nsresult GetNamedObject(JSContext* aContext, jsval aID, JSObject** aObj);
nsresult AddElementToTable(nsIFormControl* aChild, const nsString& aName);
nsresult RemoveElementFromTable(nsIFormControl* aChild, PRBool aChildIsRef);
#ifdef DEBUG #ifdef DEBUG
nsresult SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const; nsresult SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const;
#endif #endif
@ -145,6 +153,9 @@ public:
void *mScriptObject; void *mScriptObject;
nsVoidArray mElements; nsVoidArray mElements;
nsIDOMHTMLFormElement* mForm; // WEAK - the form owns me nsIDOMHTMLFormElement* mForm; // WEAK - the form owns me
protected:
nsHashtable* mLookupTable; // A map from an ID or NAME attribute to the form control
}; };
// nsHTMLFormElement implementation // nsHTMLFormElement implementation
@ -474,16 +485,27 @@ nsHTMLFormElement::AddElement(nsIFormControl* aChild)
if (rv) { if (rv) {
NS_ADDREF(aChild); NS_ADDREF(aChild);
} }
return rv; return rv;
} }
NS_IMETHODIMP
nsHTMLFormElement::AddElementToTable(nsIFormControl* aChild, const nsString& aName)
{
return mControls->AddElementToTable(aChild, aName);
}
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLFormElement::RemoveElement(nsIFormControl* aChild, PRBool aChildIsRef) nsHTMLFormElement::RemoveElement(nsIFormControl* aChild, PRBool aChildIsRef)
{ {
PRBool rv = mControls->mElements.RemoveElement(aChild); PRBool rv = mControls->mElements.RemoveElement(aChild);
if (rv && aChildIsRef) { if (rv) {
mControls->RemoveElementFromTable(aChild, aChildIsRef);
if (aChildIsRef) {
NS_RELEASE(aChild); NS_RELEASE(aChild);
} }
}
return rv; return rv;
} }
@ -701,10 +723,15 @@ nsFormControlList::nsFormControlList(nsIDOMHTMLFormElement* aForm)
NS_INIT_REFCNT(); NS_INIT_REFCNT();
mScriptObject = nsnull; mScriptObject = nsnull;
mForm = aForm; // WEAK - the form owns me mForm = aForm; // WEAK - the form owns me
mLookupTable = nsnull;
} }
nsFormControlList::~nsFormControlList() nsFormControlList::~nsFormControlList()
{ {
if (mLookupTable) {
delete mLookupTable;
mLookupTable = nsnull;
}
mForm = nsnull; mForm = nsnull;
Clear(); Clear();
} }
@ -728,6 +755,9 @@ nsFormControlList::Clear()
PRUint32 numElements = mElements.Count(); PRUint32 numElements = mElements.Count();
for (PRUint32 i = 0; i < numElements; i++) { for (PRUint32 i = 0; i < numElements; i++) {
nsIFormControl* elem = (nsIFormControl*) mElements.ElementAt(i); nsIFormControl* elem = (nsIFormControl*) mElements.ElementAt(i);
if (mLookupTable) {
RemoveElementFromTable(elem, PR_TRUE);
}
NS_IF_RELEASE(elem); NS_IF_RELEASE(elem);
} }
} }
@ -947,33 +977,59 @@ nsFormControlList::NamedItem(JSContext* cx, jsval* argv, PRUint32 argc, jsval* a
NS_IMETHODIMP NS_IMETHODIMP
nsFormControlList::NamedItem(const nsString& aName, nsIDOMNode** aReturn) nsFormControlList::NamedItem(const nsString& aName, nsIDOMNode** aReturn)
{ {
PRUint32 count = mElements.Count();
nsresult result = NS_OK; nsresult result = NS_OK;
nsStringKey key(aName);
nsIFormControl* control = nsnull;
*aReturn = nsnull; *aReturn = nsnull;
for (PRUint32 i = 0; i < count && *aReturn == nsnull; i++) {
nsIFormControl *control = (nsIFormControl*)mElements.ElementAt(i);
if (nsnull != control) {
nsIContent *content;
result = control->QueryInterface(kIContentIID, (void **)&content); if (mLookupTable) {
if (NS_OK == result) { control = (nsIFormControl*) mLookupTable->Get(&key);
nsAutoString name; }
// XXX Should it be an EqualsIgnoreCase?
if (((content->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::name, name) == NS_CONTENT_ATTR_HAS_VALUE) && if (control) {
(aName.Equals(name))) ||
((content->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::id, name) == NS_CONTENT_ATTR_HAS_VALUE) &&
(aName.Equals(name)))) {
result = control->QueryInterface(kIDOMNodeIID, (void **)aReturn); result = control->QueryInterface(kIDOMNodeIID, (void **)aReturn);
} }
NS_RELEASE(content);
}
}
}
return result; return result;
} }
nsresult
nsFormControlList::AddElementToTable(nsIFormControl* aChild, const nsString& aName)
{
nsStringKey key(aName);
if (!mLookupTable)
mLookupTable = (nsHashtable*) new nsHashtable(NS_FORM_CONTROL_LIST_HASHTABLE_SIZE);
mLookupTable->Put(&key, NS_STATIC_CAST(void*, aChild));
return NS_OK;
}
nsresult
nsFormControlList::RemoveElementFromTable(nsIFormControl* aChild, PRBool aChildIsRef)
{
// This nsIContent* cannot be a COM pointer because it shouldn't
// be released at the end of this function when aChildIsRef is FALSE.
nsIContent* content = nsnull;
nsAutoString name;
aChild->QueryInterface(kIContentIID, (void**) &content);
if (mLookupTable && content &&
(content->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::name, name) == NS_CONTENT_ATTR_HAS_VALUE ||
content->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::id, name) == NS_CONTENT_ATTR_HAS_VALUE))
{
nsStringKey key(name);
mLookupTable->Remove(&key);
}
if (aChildIsRef)
{
NS_RELEASE(content);
}
return NS_OK;
}
#ifdef DEBUG #ifdef DEBUG
nsresult nsresult
nsFormControlList::SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const nsFormControlList::SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const

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

@ -159,7 +159,7 @@ protected:
nsresult GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd); nsresult GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd);
protected: protected:
nsGenericHTMLLeafElement mInner; nsGenericHTMLLeafFormElement mInner;
nsIForm* mForm; nsIForm* mForm;
PRInt32 mType; PRInt32 mType;
PRBool mSkipFocusEvent; PRBool mSkipFocusEvent;
@ -167,6 +167,7 @@ protected:
nsCOMPtr<nsIXBLBinding> mBinding; nsCOMPtr<nsIXBLBinding> mBinding;
PRBool mDidMouseDown; PRBool mDidMouseDown;
PRBool IsImage() const { PRBool IsImage() const {
nsAutoString tmp; nsAutoString tmp;
mInner.GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::type, tmp); mInner.GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::type, tmp);
@ -1072,6 +1073,9 @@ nsHTMLInputElement::SetForm(nsIDOMHTMLFormElement* aForm)
} }
} }
NS_IF_RELEASE(formControl); NS_IF_RELEASE(formControl);
mInner.SetForm(mForm);
return result; return result;
} }

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

@ -128,7 +128,7 @@ public:
NS_IMETHOD Init() { return NS_OK; } NS_IMETHOD Init() { return NS_OK; }
protected: protected:
nsGenericHTMLContainerElement mInner; nsGenericHTMLContainerFormElement mInner;
nsIForm* mForm; nsIForm* mForm;
}; };
@ -272,6 +272,9 @@ nsHTMLLabelElement::SetForm(nsIDOMHTMLFormElement* aForm)
} }
} }
NS_IF_RELEASE(formControl); NS_IF_RELEASE(formControl);
mInner.SetForm(mForm);
return result; return result;
} }

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

@ -83,7 +83,7 @@ public:
protected: protected:
nsGenericHTMLContainerElement mInner; nsGenericHTMLContainerFormElement mInner;
nsIForm* mForm; nsIForm* mForm;
}; };
@ -199,6 +199,9 @@ nsHTMLLegendElement::SetForm(nsIDOMHTMLFormElement* aForm)
NS_RELEASE(formControl); NS_RELEASE(formControl);
} }
} }
mInner.SetForm(mForm);
return result; return result;
} }

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

@ -108,7 +108,7 @@ protected:
nsGenericHTMLContainerElement mInner; nsGenericHTMLContainerElement mInner;
// Get the primary frame associated with this content // Get the primary frame associated with this content
nsresult GetPrimaryFrame(nsIFormControlFrame *&aFormControlFrame); nsresult GetPrimaryFrame(nsIFormControlFrame *&aFormControlFrame, PRBool aFlushNotifications = PR_TRUE);
// Get the select content element that contains this option // Get the select content element that contains this option
nsresult GetSelect(nsIDOMHTMLSelectElement *&aSelectElement); nsresult GetSelect(nsIDOMHTMLSelectElement *&aSelectElement);
@ -256,7 +256,7 @@ NS_IMETHODIMP
nsHTMLOptionElement::SetSelected(PRBool aValue) nsHTMLOptionElement::SetSelected(PRBool aValue)
{ {
nsIFormControlFrame* fcFrame = nsnull; nsIFormControlFrame* fcFrame = nsnull;
nsresult result = GetPrimaryFrame(fcFrame); nsresult result = GetPrimaryFrame(fcFrame, PR_FALSE);
if (NS_SUCCEEDED(result) && (nsnull != fcFrame)) { if (NS_SUCCEEDED(result) && (nsnull != fcFrame)) {
nsISelectControlFrame* selectFrame = nsnull; nsISelectControlFrame* selectFrame = nsnull;
result = fcFrame->QueryInterface(NS_GET_IID(nsISelectControlFrame),(void **) &selectFrame); result = fcFrame->QueryInterface(NS_GET_IID(nsISelectControlFrame),(void **) &selectFrame);
@ -542,7 +542,7 @@ nsHTMLOptionElement::SetText(const nsString& aText)
// Options don't have frames - get the select content node // Options don't have frames - get the select content node
// then call nsGenericHTMLElement::GetPrimaryFrame() // then call nsGenericHTMLElement::GetPrimaryFrame()
nsresult nsHTMLOptionElement::GetPrimaryFrame(nsIFormControlFrame *&aIFormControlFrame) nsresult nsHTMLOptionElement::GetPrimaryFrame(nsIFormControlFrame *&aIFormControlFrame, PRBool aFlushNotifications)
{ {
nsIDOMHTMLSelectElement* selectElement = nsnull; nsIDOMHTMLSelectElement* selectElement = nsnull;
nsresult res = GetSelect(selectElement); nsresult res = GetSelect(selectElement);
@ -552,7 +552,7 @@ nsresult nsHTMLOptionElement::GetPrimaryFrame(nsIFormControlFrame *&aIFormContro
NS_RELEASE(selectElement); NS_RELEASE(selectElement);
if (NS_OK == gotContent) { if (NS_OK == gotContent) {
res = nsGenericHTMLElement::GetPrimaryFrame(selectContent, aIFormControlFrame); res = nsGenericHTMLElement::GetPrimaryFrame(selectContent, aIFormControlFrame, aFlushNotifications);
NS_RELEASE(selectContent); NS_RELEASE(selectContent);
} }
} }

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

@ -209,7 +209,7 @@ public:
protected: protected:
NS_IMETHOD GetPresState(nsIPresState** aPresState, nsISupportsArray** aValueArray); NS_IMETHOD GetPresState(nsIPresState** aPresState, nsISupportsArray** aValueArray);
nsGenericHTMLContainerElement mInner; nsGenericHTMLContainerFormElement mInner;
nsIForm* mForm; nsIForm* mForm;
nsHTMLOptionCollection* mOptions; nsHTMLOptionCollection* mOptions;
PRBool mIsDoneAddingContent; PRBool mIsDoneAddingContent;
@ -1128,6 +1128,9 @@ nsHTMLSelectElement::SetForm(nsIDOMHTMLFormElement* aForm)
} }
} }
NS_IF_RELEASE(formControl); NS_IF_RELEASE(formControl);
mInner.SetForm(mForm);
return result; return result;
} }

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

@ -125,7 +125,7 @@ public:
NS_IMETHOD GetBaseTag(nsIAtom** aResult); NS_IMETHOD GetBaseTag(nsIAtom** aResult);
protected: protected:
nsGenericHTMLContainerElement mInner; nsGenericHTMLContainerFormElement mInner;
nsIForm* mForm; nsIForm* mForm;
nsCOMPtr<nsIControllers> mControllers; nsCOMPtr<nsIControllers> mControllers;
nsCOMPtr<nsIXBLBinding> mBinding; nsCOMPtr<nsIXBLBinding> mBinding;
@ -564,6 +564,9 @@ nsHTMLTextAreaElement::SetForm(nsIDOMHTMLFormElement* aForm)
} }
} }
NS_IF_RELEASE(formControl); NS_IF_RELEASE(formControl);
mInner.SetForm(mForm);
return result; return result;
} }

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

@ -23,6 +23,7 @@
#define nsIForm_h___ #define nsIForm_h___
#include "nsISupports.h" #include "nsISupports.h"
#include "nsString.h"
class nsIFormControl; class nsIFormControl;
class nsISizeOfHandler; class nsISizeOfHandler;
@ -51,6 +52,15 @@ public:
*/ */
NS_IMETHOD AddElement(nsIFormControl* aElement) = 0; NS_IMETHOD AddElement(nsIFormControl* aElement) = 0;
/**
* Add an element to the lookup table mainted by the form.
* We can't fold this method into AddElement() because when
* AddElement() is called, the form control has no
* attributes. The name or id attributes of the form control
* are used as a key into the table.
*/
NS_IMETHOD AddElementToTable(nsIFormControl* aElement, const nsString& aName) = 0;
/** /**
* Get the element at a specified index position * Get the element at a specified index position
* @param aIndex the index * @param aIndex the index

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

@ -3121,3 +3121,69 @@ nsGenericHTMLContainerElement::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
return NS_OK; return NS_OK;
} }
//----------------------------------------------------------------------
nsGenericHTMLContainerFormElement::nsGenericHTMLContainerFormElement()
{
mForm = nsnull;
}
nsGenericHTMLContainerFormElement::~nsGenericHTMLContainerFormElement()
{
// Do nothing
}
nsresult
nsGenericHTMLContainerFormElement::SetForm(nsIForm* aForm)
{
mForm = aForm;
return NS_OK;
}
nsresult
nsGenericHTMLContainerFormElement::SetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName, const nsString& aValue,
PRBool aNotify)
{
// Add the control to the hash table
nsCOMPtr<nsIFormControl> control;
control = do_QueryInterface(mContent);
if (mForm && (nsHTMLAtoms::name == aName || nsHTMLAtoms::id == aName))
mForm->AddElementToTable(control, aValue);
return nsGenericHTMLElement::SetAttribute(aNameSpaceID, aName, aValue, aNotify);
}
//----------------------------------------------------------------------
nsGenericHTMLLeafFormElement::nsGenericHTMLLeafFormElement()
{
mForm = nsnull;
}
nsGenericHTMLLeafFormElement::~nsGenericHTMLLeafFormElement()
{
// Do nothing
}
nsresult
nsGenericHTMLLeafFormElement::SetForm(nsIForm* aForm)
{
mForm = aForm;
return NS_OK;
}
nsresult
nsGenericHTMLLeafFormElement::SetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName, const nsString& aValue,
PRBool aNotify)
{
// Add the control to the hash table
nsCOMPtr<nsIFormControl> control;
control = do_QueryInterface(mContent);
if (mForm && (nsHTMLAtoms::name == aName || nsHTMLAtoms::id == aName))
mForm->AddElementToTable(control, aValue);
return nsGenericHTMLElement::SetAttribute(aNameSpaceID, aName, aValue, aNotify);
}
//----------------------------------------------------------------------

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

@ -454,6 +454,42 @@ public:
//---------------------------------------------------------------------- //----------------------------------------------------------------------
class nsGenericHTMLContainerFormElement : public nsGenericHTMLContainerElement {
public:
nsGenericHTMLContainerFormElement();
~nsGenericHTMLContainerFormElement();
nsresult SetForm(nsIForm* aForm);
nsresult SetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName, const nsString& aValue,
PRBool aNotify);
nsresult SetAttribute(const nsString& aName, const nsString& aValue)
{
return nsGenericHTMLElement::SetAttribute(aName, aValue);
}
nsIForm* mForm;
};
//----------------------------------------------------------------------
class nsGenericHTMLLeafFormElement : public nsGenericHTMLLeafElement {
public:
nsGenericHTMLLeafFormElement();
~nsGenericHTMLLeafFormElement();
nsresult SetForm(nsIForm* aForm);
nsresult SetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName, const nsString& aValue,
PRBool aNotify);
nsresult SetAttribute(const nsString& aName, const nsString& aValue)
{
return nsGenericHTMLElement::SetAttribute(aName, aValue);
}
nsIForm* mForm;
};
//----------------------------------------------------------------------
/** /**
* Implement the nsIDOMHTMLElement API by forwarding the methods to a * Implement the nsIDOMHTMLElement API by forwarding the methods to a
* generic content object (either nsGenericHTMLLeafElement or * generic content object (either nsGenericHTMLLeafElement or

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

@ -97,7 +97,7 @@ public:
NS_IMETHOD Init() { return NS_OK; } NS_IMETHOD Init() { return NS_OK; }
protected: protected:
nsGenericHTMLContainerElement mInner; nsGenericHTMLContainerFormElement mInner;
nsIForm* mForm; nsIForm* mForm;
PRInt32 mType; PRInt32 mType;
}; };
@ -528,6 +528,9 @@ nsHTMLButtonElement::SetForm(nsIDOMHTMLFormElement* aForm)
} }
} }
NS_IF_RELEASE(formControl); NS_IF_RELEASE(formControl);
mInner.SetForm(mForm);
return result; return result;
} }

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

@ -79,7 +79,7 @@ public:
NS_IMETHOD Init() { return NS_OK; } NS_IMETHOD Init() { return NS_OK; }
protected: protected:
nsGenericHTMLContainerElement mInner; nsGenericHTMLContainerFormElement mInner;
nsIForm* mForm; nsIForm* mForm;
}; };
@ -224,6 +224,9 @@ nsHTMLFieldSetElement::SetForm(nsIDOMHTMLFormElement* aForm)
} }
} }
NS_IF_RELEASE(formControl); NS_IF_RELEASE(formControl);
mInner.SetForm(mForm);
return result; return result;
} }

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

@ -44,6 +44,9 @@
#include "nsIScriptGlobalObject.h" #include "nsIScriptGlobalObject.h"
#include "nsDOMError.h" #include "nsDOMError.h"
#include "nsLayoutUtils.h" #include "nsLayoutUtils.h"
#include "nsHashTable.h"
static const int NS_FORM_CONTROL_LIST_HASHTABLE_SIZE = 64;
static NS_DEFINE_IID(kIDOMHTMLFormElementIID, NS_IDOMHTMLFORMELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLFormElementIID, NS_IDOMHTMLFORMELEMENT_IID);
static NS_DEFINE_IID(kIFormControlIID, NS_IFORMCONTROL_IID); static NS_DEFINE_IID(kIFormControlIID, NS_IFORMCONTROL_IID);
@ -109,6 +112,7 @@ public:
// nsIForm // nsIForm
NS_IMETHOD AddElement(nsIFormControl* aElement); NS_IMETHOD AddElement(nsIFormControl* aElement);
NS_IMETHOD AddElementToTable(nsIFormControl* aChild, const nsString& aName);
NS_IMETHOD GetElementAt(PRInt32 aIndex, nsIFormControl** aElement) const; NS_IMETHOD GetElementAt(PRInt32 aIndex, nsIFormControl** aElement) const;
NS_IMETHOD GetElementCount(PRUint32* aCount) const; NS_IMETHOD GetElementCount(PRUint32* aCount) const;
NS_IMETHOD RemoveElement(nsIFormControl* aElement, PRBool aChildIsRef = PR_TRUE); NS_IMETHOD RemoveElement(nsIFormControl* aElement, PRBool aChildIsRef = PR_TRUE);
@ -138,6 +142,10 @@ public:
NS_DECL_IDOMHTMLFORMCONTROLLIST NS_DECL_IDOMHTMLFORMCONTROLLIST
nsresult GetNamedObject(JSContext* aContext, jsval aID, JSObject** aObj); nsresult GetNamedObject(JSContext* aContext, jsval aID, JSObject** aObj);
nsresult AddElementToTable(nsIFormControl* aChild, const nsString& aName);
nsresult RemoveElementFromTable(nsIFormControl* aChild, PRBool aChildIsRef);
#ifdef DEBUG #ifdef DEBUG
nsresult SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const; nsresult SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const;
#endif #endif
@ -145,6 +153,9 @@ public:
void *mScriptObject; void *mScriptObject;
nsVoidArray mElements; nsVoidArray mElements;
nsIDOMHTMLFormElement* mForm; // WEAK - the form owns me nsIDOMHTMLFormElement* mForm; // WEAK - the form owns me
protected:
nsHashtable* mLookupTable; // A map from an ID or NAME attribute to the form control
}; };
// nsHTMLFormElement implementation // nsHTMLFormElement implementation
@ -474,16 +485,27 @@ nsHTMLFormElement::AddElement(nsIFormControl* aChild)
if (rv) { if (rv) {
NS_ADDREF(aChild); NS_ADDREF(aChild);
} }
return rv; return rv;
} }
NS_IMETHODIMP
nsHTMLFormElement::AddElementToTable(nsIFormControl* aChild, const nsString& aName)
{
return mControls->AddElementToTable(aChild, aName);
}
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLFormElement::RemoveElement(nsIFormControl* aChild, PRBool aChildIsRef) nsHTMLFormElement::RemoveElement(nsIFormControl* aChild, PRBool aChildIsRef)
{ {
PRBool rv = mControls->mElements.RemoveElement(aChild); PRBool rv = mControls->mElements.RemoveElement(aChild);
if (rv && aChildIsRef) { if (rv) {
mControls->RemoveElementFromTable(aChild, aChildIsRef);
if (aChildIsRef) {
NS_RELEASE(aChild); NS_RELEASE(aChild);
} }
}
return rv; return rv;
} }
@ -701,10 +723,15 @@ nsFormControlList::nsFormControlList(nsIDOMHTMLFormElement* aForm)
NS_INIT_REFCNT(); NS_INIT_REFCNT();
mScriptObject = nsnull; mScriptObject = nsnull;
mForm = aForm; // WEAK - the form owns me mForm = aForm; // WEAK - the form owns me
mLookupTable = nsnull;
} }
nsFormControlList::~nsFormControlList() nsFormControlList::~nsFormControlList()
{ {
if (mLookupTable) {
delete mLookupTable;
mLookupTable = nsnull;
}
mForm = nsnull; mForm = nsnull;
Clear(); Clear();
} }
@ -728,6 +755,9 @@ nsFormControlList::Clear()
PRUint32 numElements = mElements.Count(); PRUint32 numElements = mElements.Count();
for (PRUint32 i = 0; i < numElements; i++) { for (PRUint32 i = 0; i < numElements; i++) {
nsIFormControl* elem = (nsIFormControl*) mElements.ElementAt(i); nsIFormControl* elem = (nsIFormControl*) mElements.ElementAt(i);
if (mLookupTable) {
RemoveElementFromTable(elem, PR_TRUE);
}
NS_IF_RELEASE(elem); NS_IF_RELEASE(elem);
} }
} }
@ -947,33 +977,59 @@ nsFormControlList::NamedItem(JSContext* cx, jsval* argv, PRUint32 argc, jsval* a
NS_IMETHODIMP NS_IMETHODIMP
nsFormControlList::NamedItem(const nsString& aName, nsIDOMNode** aReturn) nsFormControlList::NamedItem(const nsString& aName, nsIDOMNode** aReturn)
{ {
PRUint32 count = mElements.Count();
nsresult result = NS_OK; nsresult result = NS_OK;
nsStringKey key(aName);
nsIFormControl* control = nsnull;
*aReturn = nsnull; *aReturn = nsnull;
for (PRUint32 i = 0; i < count && *aReturn == nsnull; i++) {
nsIFormControl *control = (nsIFormControl*)mElements.ElementAt(i);
if (nsnull != control) {
nsIContent *content;
result = control->QueryInterface(kIContentIID, (void **)&content); if (mLookupTable) {
if (NS_OK == result) { control = (nsIFormControl*) mLookupTable->Get(&key);
nsAutoString name; }
// XXX Should it be an EqualsIgnoreCase?
if (((content->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::name, name) == NS_CONTENT_ATTR_HAS_VALUE) && if (control) {
(aName.Equals(name))) ||
((content->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::id, name) == NS_CONTENT_ATTR_HAS_VALUE) &&
(aName.Equals(name)))) {
result = control->QueryInterface(kIDOMNodeIID, (void **)aReturn); result = control->QueryInterface(kIDOMNodeIID, (void **)aReturn);
} }
NS_RELEASE(content);
}
}
}
return result; return result;
} }
nsresult
nsFormControlList::AddElementToTable(nsIFormControl* aChild, const nsString& aName)
{
nsStringKey key(aName);
if (!mLookupTable)
mLookupTable = (nsHashtable*) new nsHashtable(NS_FORM_CONTROL_LIST_HASHTABLE_SIZE);
mLookupTable->Put(&key, NS_STATIC_CAST(void*, aChild));
return NS_OK;
}
nsresult
nsFormControlList::RemoveElementFromTable(nsIFormControl* aChild, PRBool aChildIsRef)
{
// This nsIContent* cannot be a COM pointer because it shouldn't
// be released at the end of this function when aChildIsRef is FALSE.
nsIContent* content = nsnull;
nsAutoString name;
aChild->QueryInterface(kIContentIID, (void**) &content);
if (mLookupTable && content &&
(content->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::name, name) == NS_CONTENT_ATTR_HAS_VALUE ||
content->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::id, name) == NS_CONTENT_ATTR_HAS_VALUE))
{
nsStringKey key(name);
mLookupTable->Remove(&key);
}
if (aChildIsRef)
{
NS_RELEASE(content);
}
return NS_OK;
}
#ifdef DEBUG #ifdef DEBUG
nsresult nsresult
nsFormControlList::SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const nsFormControlList::SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const

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

@ -159,7 +159,7 @@ protected:
nsresult GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd); nsresult GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd);
protected: protected:
nsGenericHTMLLeafElement mInner; nsGenericHTMLLeafFormElement mInner;
nsIForm* mForm; nsIForm* mForm;
PRInt32 mType; PRInt32 mType;
PRBool mSkipFocusEvent; PRBool mSkipFocusEvent;
@ -167,6 +167,7 @@ protected:
nsCOMPtr<nsIXBLBinding> mBinding; nsCOMPtr<nsIXBLBinding> mBinding;
PRBool mDidMouseDown; PRBool mDidMouseDown;
PRBool IsImage() const { PRBool IsImage() const {
nsAutoString tmp; nsAutoString tmp;
mInner.GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::type, tmp); mInner.GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::type, tmp);
@ -1072,6 +1073,9 @@ nsHTMLInputElement::SetForm(nsIDOMHTMLFormElement* aForm)
} }
} }
NS_IF_RELEASE(formControl); NS_IF_RELEASE(formControl);
mInner.SetForm(mForm);
return result; return result;
} }

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

@ -128,7 +128,7 @@ public:
NS_IMETHOD Init() { return NS_OK; } NS_IMETHOD Init() { return NS_OK; }
protected: protected:
nsGenericHTMLContainerElement mInner; nsGenericHTMLContainerFormElement mInner;
nsIForm* mForm; nsIForm* mForm;
}; };
@ -272,6 +272,9 @@ nsHTMLLabelElement::SetForm(nsIDOMHTMLFormElement* aForm)
} }
} }
NS_IF_RELEASE(formControl); NS_IF_RELEASE(formControl);
mInner.SetForm(mForm);
return result; return result;
} }

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

@ -83,7 +83,7 @@ public:
protected: protected:
nsGenericHTMLContainerElement mInner; nsGenericHTMLContainerFormElement mInner;
nsIForm* mForm; nsIForm* mForm;
}; };
@ -199,6 +199,9 @@ nsHTMLLegendElement::SetForm(nsIDOMHTMLFormElement* aForm)
NS_RELEASE(formControl); NS_RELEASE(formControl);
} }
} }
mInner.SetForm(mForm);
return result; return result;
} }

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

@ -108,7 +108,7 @@ protected:
nsGenericHTMLContainerElement mInner; nsGenericHTMLContainerElement mInner;
// Get the primary frame associated with this content // Get the primary frame associated with this content
nsresult GetPrimaryFrame(nsIFormControlFrame *&aFormControlFrame); nsresult GetPrimaryFrame(nsIFormControlFrame *&aFormControlFrame, PRBool aFlushNotifications = PR_TRUE);
// Get the select content element that contains this option // Get the select content element that contains this option
nsresult GetSelect(nsIDOMHTMLSelectElement *&aSelectElement); nsresult GetSelect(nsIDOMHTMLSelectElement *&aSelectElement);
@ -256,7 +256,7 @@ NS_IMETHODIMP
nsHTMLOptionElement::SetSelected(PRBool aValue) nsHTMLOptionElement::SetSelected(PRBool aValue)
{ {
nsIFormControlFrame* fcFrame = nsnull; nsIFormControlFrame* fcFrame = nsnull;
nsresult result = GetPrimaryFrame(fcFrame); nsresult result = GetPrimaryFrame(fcFrame, PR_FALSE);
if (NS_SUCCEEDED(result) && (nsnull != fcFrame)) { if (NS_SUCCEEDED(result) && (nsnull != fcFrame)) {
nsISelectControlFrame* selectFrame = nsnull; nsISelectControlFrame* selectFrame = nsnull;
result = fcFrame->QueryInterface(NS_GET_IID(nsISelectControlFrame),(void **) &selectFrame); result = fcFrame->QueryInterface(NS_GET_IID(nsISelectControlFrame),(void **) &selectFrame);
@ -542,7 +542,7 @@ nsHTMLOptionElement::SetText(const nsString& aText)
// Options don't have frames - get the select content node // Options don't have frames - get the select content node
// then call nsGenericHTMLElement::GetPrimaryFrame() // then call nsGenericHTMLElement::GetPrimaryFrame()
nsresult nsHTMLOptionElement::GetPrimaryFrame(nsIFormControlFrame *&aIFormControlFrame) nsresult nsHTMLOptionElement::GetPrimaryFrame(nsIFormControlFrame *&aIFormControlFrame, PRBool aFlushNotifications)
{ {
nsIDOMHTMLSelectElement* selectElement = nsnull; nsIDOMHTMLSelectElement* selectElement = nsnull;
nsresult res = GetSelect(selectElement); nsresult res = GetSelect(selectElement);
@ -552,7 +552,7 @@ nsresult nsHTMLOptionElement::GetPrimaryFrame(nsIFormControlFrame *&aIFormContro
NS_RELEASE(selectElement); NS_RELEASE(selectElement);
if (NS_OK == gotContent) { if (NS_OK == gotContent) {
res = nsGenericHTMLElement::GetPrimaryFrame(selectContent, aIFormControlFrame); res = nsGenericHTMLElement::GetPrimaryFrame(selectContent, aIFormControlFrame, aFlushNotifications);
NS_RELEASE(selectContent); NS_RELEASE(selectContent);
} }
} }

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

@ -209,7 +209,7 @@ public:
protected: protected:
NS_IMETHOD GetPresState(nsIPresState** aPresState, nsISupportsArray** aValueArray); NS_IMETHOD GetPresState(nsIPresState** aPresState, nsISupportsArray** aValueArray);
nsGenericHTMLContainerElement mInner; nsGenericHTMLContainerFormElement mInner;
nsIForm* mForm; nsIForm* mForm;
nsHTMLOptionCollection* mOptions; nsHTMLOptionCollection* mOptions;
PRBool mIsDoneAddingContent; PRBool mIsDoneAddingContent;
@ -1128,6 +1128,9 @@ nsHTMLSelectElement::SetForm(nsIDOMHTMLFormElement* aForm)
} }
} }
NS_IF_RELEASE(formControl); NS_IF_RELEASE(formControl);
mInner.SetForm(mForm);
return result; return result;
} }

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

@ -125,7 +125,7 @@ public:
NS_IMETHOD GetBaseTag(nsIAtom** aResult); NS_IMETHOD GetBaseTag(nsIAtom** aResult);
protected: protected:
nsGenericHTMLContainerElement mInner; nsGenericHTMLContainerFormElement mInner;
nsIForm* mForm; nsIForm* mForm;
nsCOMPtr<nsIControllers> mControllers; nsCOMPtr<nsIControllers> mControllers;
nsCOMPtr<nsIXBLBinding> mBinding; nsCOMPtr<nsIXBLBinding> mBinding;
@ -564,6 +564,9 @@ nsHTMLTextAreaElement::SetForm(nsIDOMHTMLFormElement* aForm)
} }
} }
NS_IF_RELEASE(formControl); NS_IF_RELEASE(formControl);
mInner.SetForm(mForm);
return result; return result;
} }