diff --git a/content/html/content/public/nsIForm.h b/content/html/content/public/nsIForm.h index e525219b61f2..6ca7f6c73f90 100644 --- a/content/html/content/public/nsIForm.h +++ b/content/html/content/public/nsIForm.h @@ -43,7 +43,6 @@ class nsIFormControl; class nsISimpleEnumerator; class nsIURI; -template class nsTArray; #define NS_FORM_METHOD_GET 0 #define NS_FORM_METHOD_POST 1 @@ -53,13 +52,12 @@ template class nsTArray; // IID for the nsIForm interface #define NS_IFORM_IID \ -{ 0x6e8456c2, 0xcf49, 0x4b6d, \ - { 0xb5, 0xfe, 0x80, 0x0d, 0x03, 0x4f, 0x55, 0x33 } } +{ 0x27f1ff6c, 0xeb78, 0x405b, \ + { 0xa6, 0xeb, 0xf0, 0xce, 0xa8, 0x30, 0x85, 0x58 } } /** - * This interface provides a complete set of methods dealing with - * elements which belong to a form element. When nsIDOMHTMLCollection - * allows write operations + * This interface provides some methods that can be used to access the + * guts of a form. It's being slowly phased out. */ class nsIForm : public nsISupports @@ -67,27 +65,6 @@ class nsIForm : public nsISupports public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFORM_IID) - /** - * Add an element to end of this form's list of elements - * - * @param aElement the element to add - * @param aNotify If true, send nsIDocumentObserver notifications as needed. - * @return NS_OK if the element was successfully added - */ - NS_IMETHOD AddElement(nsIFormControl* aElement, - PRBool aNotify) = 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 nsAString& aName) = 0; - /** * Get the element at a specified index position in form.elements * @@ -95,7 +72,7 @@ public: * @param aElement the element at that index * @return NS_OK if there was an element at that position, -1 otherwise */ - NS_IMETHOD GetElementAt(PRInt32 aIndex, nsIFormControl** aElement) const = 0; + NS_IMETHOD_(nsIFormControl*) GetElementAt(PRInt32 aIndex) const = 0; /** * Get the number of elements in form.elements @@ -105,30 +82,6 @@ public: */ NS_IMETHOD_(PRUint32) GetElementCount() const = 0; - /** - * Remove an element from this form's list of elements - * - * @param aElement the element to remove - * @param aNotify If true, send nsIDocumentObserver notifications as needed. - * @return NS_OK if the element was successfully removed. - */ - NS_IMETHOD RemoveElement(nsIFormControl* aElement, - PRBool aNotify) = 0; - - /** - * Remove an element from the lookup table mainted by the form. - * We can't fold this method into RemoveElement() because when - * RemoveElement() is called it doesn't know if the element is - * removed because the id attribute has changed, or bacause the - * name attribute has changed. - * - * @param aElement the element to remove - * @param aName the name or id of the element to remove - * @return NS_OK if the element was successfully removed. - */ - NS_IMETHOD RemoveElementFromTable(nsIFormControl* aElement, - const nsAString& aName) = 0; - /** * Resolve a name in the scope of the form object, this means find * form controls in this form with the correct value in the name @@ -147,68 +100,11 @@ public: */ NS_IMETHOD_(PRInt32) IndexOfControl(nsIFormControl* aControl) = 0; - /** - * Flag the form to know that a button or image triggered scripted form - * submission. In that case the form will defer the submission until the - * script handler returns and the return value is known. - */ - NS_IMETHOD OnSubmitClickBegin() = 0; - NS_IMETHOD OnSubmitClickEnd() = 0; - - /** - * Flush a possible pending submission. If there was a scripted submission - * triggered by a button or image, the submission was defered. This method - * forces the pending submission to be submitted. (happens when the handler - * returns false or there is an action/target change in the script) - */ - NS_IMETHOD FlushPendingSubmission() = 0; - /** - * Forget a possible pending submission. Same as above but this time we - * get rid of the pending submission cause the handler returned true - * so we will rebuild the submission with the name/value of the triggering - * element - */ - NS_IMETHOD ForgetPendingSubmission() = 0; - - /** - * Get the full URL to submit to. Do not submit if the returned URL is null. - * - * @param aActionURL the full, unadulterated URL you'll be submitting to [OUT] - */ - NS_IMETHOD GetActionURL(nsIURI** aActionURL) = 0; - - /** - * Get the list of all the form's controls in document order. - * This list contains all form control elements, not just those - * returned by form.elements in JS. The controls in this list do - * not have additional references added. - * - * @param aControls Sorted list of form controls [out]. - * @return NS_OK if the list was successfully created. - */ - NS_IMETHOD GetSortedControls(nsTArray& aControls) const = 0; - /** * Get the default submit element. If there's no default submit element, * return null. */ NS_IMETHOD_(nsIFormControl*) GetDefaultSubmitElement() const = 0; - - /** - * Check whether a given nsIFormControl is the default submit - * element. This is different from just comparing to - * GetDefaultSubmitElement() in certain situations inside an update - * when GetDefaultSubmitElement() might not be up to date. aControl - * is expected to not be null. - */ - NS_IMETHOD_(PRBool) IsDefaultSubmitElement(const nsIFormControl* aControl) const = 0; - - /** - * Return whether there is one and only one input text control. - * - * @return Whether there is exactly one input text control. - */ - NS_IMETHOD_(PRBool) HasSingleTextControl() const = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIForm, NS_IFORM_IID) diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index e38efb375136..5ebcee1958f4 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -98,6 +98,7 @@ #include "nsIForm.h" #include "nsIFormControl.h" #include "nsIDOMHTMLFormElement.h" +#include "nsHTMLFormElement.h" #include "nsFocusManager.h" #include "nsMutationEvent.h" @@ -897,8 +898,8 @@ nsGenericHTMLElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) nsGenericElement::UnbindFromTree(aDeep, aNullParent); } -already_AddRefed -nsGenericHTMLElement::FindForm(nsIForm* aCurrentForm) +nsHTMLFormElement* +nsGenericHTMLElement::FindForm(nsHTMLFormElement* aCurrentForm) { // Make sure we don't end up finding a form that's anonymous from // our point of view. @@ -921,10 +922,7 @@ nsGenericHTMLElement::FindForm(nsIForm* aCurrentForm) } } #endif - nsIDOMHTMLFormElement* form; - CallQueryInterface(content, &form); - - return form; + return static_cast(content); } nsIContent *prevContent = content; @@ -938,19 +936,9 @@ nsGenericHTMLElement::FindForm(nsIForm* aCurrentForm) // we're one of those inputs-in-a-table that have a hacked mForm pointer // and a subtree containing both us and the form got removed from the // DOM. - nsCOMPtr formCOMPtr = do_QueryInterface(aCurrentForm); - NS_ASSERTION(formCOMPtr, "aCurrentForm isn't an nsIContent?"); - // Use an nsIContent temporary to reduce addref/releasing as we go up the - // tree - nsINode* iter = formCOMPtr; - do { - iter = iter->GetNodeParent(); - if (iter == prevContent) { - nsIDOMHTMLFormElement* form; - CallQueryInterface(aCurrentForm, &form); - return form; - } - } while (iter); + if (nsContentUtils::ContentIsDescendantOf(aCurrentForm, prevContent)) { + return aCurrentForm; + } } } @@ -2265,9 +2253,9 @@ nsGenericHTMLElement::SetContentEditable(const nsAString& aContentEditable) NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsGenericHTMLFrameElement, TabIndex, tabindex, 0) nsGenericHTMLFormElement::nsGenericHTMLFormElement(nsINodeInfo *aNodeInfo) - : nsGenericHTMLElement(aNodeInfo) + : nsGenericHTMLElement(aNodeInfo), + mForm(nsnull) { - mForm = nsnull; } nsGenericHTMLFormElement::~nsGenericHTMLFormElement() @@ -2302,8 +2290,7 @@ nsGenericHTMLFormElement::SetForm(nsIDOMHTMLFormElement* aForm) "We don't support switching from one non-null form to another."); // keep a *weak* ref to the form here - CallQueryInterface(aForm, &mForm); - mForm->Release(); + mForm = static_cast(aForm); } void @@ -2341,12 +2328,7 @@ NS_IMETHODIMP nsGenericHTMLFormElement::GetForm(nsIDOMHTMLFormElement** aForm) { NS_ENSURE_ARG_POINTER(aForm); - *aForm = nsnull; - - if (mForm) { - CallQueryInterface(mForm, aForm); - } - + NS_IF_ADDREF(*aForm = mForm); return NS_OK; } @@ -2434,10 +2416,7 @@ nsGenericHTMLFormElement::BindToTree(nsIDocument* aDocument, // it to the right value. Also note that even if being bound here didn't // change our parent, we still need to search, since our parent chain // probably changed _somewhere_. - nsCOMPtr form = FindForm(); - if (form) { - SetForm(form); - } + mForm = FindForm(); } if (mForm && !HasFlag(ADDED_TO_FORM)) { @@ -2476,8 +2455,7 @@ nsGenericHTMLFormElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) ClearForm(PR_TRUE, PR_TRUE); } else { // Recheck whether we should still have an mForm. - nsCOMPtr form = FindForm(mForm); - if (!form) { + if (!FindForm(mForm)) { ClearForm(PR_TRUE, PR_TRUE); } else { UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT); diff --git a/content/html/content/src/nsGenericHTMLElement.h b/content/html/content/src/nsGenericHTMLElement.h index a28da2c2048a..e200415a372c 100644 --- a/content/html/content/src/nsGenericHTMLElement.h +++ b/content/html/content/src/nsGenericHTMLElement.h @@ -62,6 +62,7 @@ class nsILayoutHistoryState; class nsIEditor; struct nsRect; struct nsSize; +class nsHTMLFormElement; typedef nsMappedAttributeElement nsGenericHTMLElementBase; @@ -506,7 +507,7 @@ public: * returned. This is needed to handle cases when HTML elements have a * current form that they're not descendants of. */ - already_AddRefed FindForm(nsIForm* aCurrentForm = nsnull); + nsHTMLFormElement* FindForm(nsHTMLFormElement* aCurrentForm = nsnull); virtual void RecompileScriptEventListeners(); @@ -855,7 +856,7 @@ protected: FocusTristate FocusState(); /** The form that contains this control */ - nsIForm* mForm; + nsHTMLFormElement* mForm; }; // If this flag is set on an nsGenericHTMLFormElement, that means that we have diff --git a/content/html/content/src/nsHTMLButtonElement.cpp b/content/html/content/src/nsHTMLButtonElement.cpp index 7df47786deb8..dd6bfd379069 100644 --- a/content/html/content/src/nsHTMLButtonElement.cpp +++ b/content/html/content/src/nsHTMLButtonElement.cpp @@ -61,6 +61,7 @@ #include "nsPresState.h" #include "nsLayoutErrors.h" #include "nsFocusManager.h" +#include "nsHTMLFormElement.h" #define NS_IN_SUBMIT_CLICK (1 << 0) #define NS_OUTER_ACTIVATE_EVENT (1 << 1) @@ -464,8 +465,9 @@ nsHTMLButtonElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor) // Using presShell to dispatch the event. It makes sure that // event is not handled if the window is being destroyed. if (presShell) { - nsCOMPtr form(do_QueryInterface(mForm)); - presShell->HandleDOMEventWithTarget(form, &event, &status); + // Hold a strong ref while dispatching + nsRefPtr form(mForm); + presShell->HandleDOMEventWithTarget(mForm, &event, &status); } } } diff --git a/content/html/content/src/nsHTMLFormElement.cpp b/content/html/content/src/nsHTMLFormElement.cpp index f81c4d609c07..61314d4c0d79 100644 --- a/content/html/content/src/nsHTMLFormElement.cpp +++ b/content/html/content/src/nsHTMLFormElement.cpp @@ -34,16 +34,10 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -#include "nsCOMPtr.h" -#include "nsIForm.h" -#include "nsIFormControl.h" -#include "nsIFormSubmission.h" -#include "nsIDOMHTMLFormElement.h" -#include "nsIDOMNSHTMLFormElement.h" +#include "nsHTMLFormElement.h" #include "nsIHTMLDocument.h" #include "nsIDOMNSHTMLFormControlList.h" #include "nsIDOMEventTarget.h" -#include "nsGenericHTMLElement.h" #include "nsEventStateManager.h" #include "nsGkAtoms.h" #include "nsStyleConsts.h" @@ -63,28 +57,23 @@ // form submission #include "nsIFormSubmitObserver.h" -#include "nsIURI.h" #include "nsIObserverService.h" #include "nsICategoryManager.h" #include "nsCategoryManagerUtils.h" #include "nsISimpleEnumerator.h" -#include "nsPIDOMWindow.h" #include "nsRange.h" #include "nsIScriptSecurityManager.h" #include "nsNetUtil.h" #include "nsIWebProgress.h" #include "nsIDocShell.h" -#include "nsIWebProgressListener.h" // radio buttons #include "nsIDOMHTMLInputElement.h" #include "nsIRadioControlElement.h" #include "nsIRadioVisitor.h" -#include "nsIRadioGroupContainer.h" #include "nsLayoutUtils.h" -#include "nsUnicharUtils.h" #include "nsEventDispatcher.h" #include "mozAutoDocUpdate.h" @@ -92,280 +81,8 @@ static const int NS_FORM_CONTROL_LIST_HASHTABLE_SIZE = 16; -class nsFormControlList; - -/** - * hashkey wrapper using nsAString KeyType - * - * @see nsTHashtable::EntryType for specification - */ -class nsStringCaseInsensitiveHashKey : public PLDHashEntryHdr -{ -public: - typedef const nsAString& KeyType; - typedef const nsAString* KeyTypePointer; - nsStringCaseInsensitiveHashKey(KeyTypePointer aStr) : mStr(*aStr) { } //take it easy just deal HashKey - nsStringCaseInsensitiveHashKey(const nsStringCaseInsensitiveHashKey& toCopy) : mStr(toCopy.mStr) { } - ~nsStringCaseInsensitiveHashKey() { } - - KeyType GetKey() const { return mStr; } - PRBool KeyEquals(const KeyTypePointer aKey) const - { - return mStr.Equals(*aKey,nsCaseInsensitiveStringComparator()); - } - - static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } - static PLDHashNumber HashKey(const KeyTypePointer aKey) - { - nsAutoString tmKey(*aKey); - ToLowerCase(tmKey); - return HashString(tmKey); - } - enum { ALLOW_MEMMOVE = PR_TRUE }; - -private: - const nsString mStr; -}; - - // nsHTMLFormElement -class nsHTMLFormElement : public nsGenericHTMLElement, - public nsIDOMHTMLFormElement, - public nsIDOMNSHTMLFormElement, - public nsIWebProgressListener, - public nsIForm, - public nsIRadioGroupContainer -{ -public: - nsHTMLFormElement(nsINodeInfo *aNodeInfo); - virtual ~nsHTMLFormElement(); - - nsresult Init(); - - // nsISupports - NS_DECL_ISUPPORTS_INHERITED - - // nsIDOMNode - NS_FORWARD_NSIDOMNODE(nsGenericHTMLElement::) - - // nsIDOMElement - NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::) - - // nsIDOMHTMLElement - NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::) - - // nsIDOMHTMLFormElement - NS_DECL_NSIDOMHTMLFORMELEMENT - - // nsIDOMNSHTMLFormElement - NS_DECL_NSIDOMNSHTMLFORMELEMENT - - // nsIWebProgressListener - NS_DECL_NSIWEBPROGRESSLISTENER - - // nsIForm - NS_IMETHOD AddElement(nsIFormControl* aElement, - PRBool aNotify); - NS_IMETHOD AddElementToTable(nsIFormControl* aChild, - const nsAString& aName); - NS_IMETHOD GetElementAt(PRInt32 aIndex, nsIFormControl** aElement) const; - NS_IMETHOD_(PRUint32) GetElementCount() const; - NS_IMETHOD RemoveElement(nsIFormControl* aElement, - PRBool aNotify); - NS_IMETHOD RemoveElementFromTable(nsIFormControl* aElement, - const nsAString& aName); - NS_IMETHOD_(already_AddRefed) ResolveName(const nsAString& aName); - NS_IMETHOD_(PRInt32) IndexOfControl(nsIFormControl* aControl); - NS_IMETHOD OnSubmitClickBegin(); - NS_IMETHOD OnSubmitClickEnd(); - NS_IMETHOD FlushPendingSubmission(); - NS_IMETHOD ForgetPendingSubmission(); - NS_IMETHOD GetActionURL(nsIURI** aActionURL); - NS_IMETHOD GetSortedControls(nsTArray& aControls) const; - NS_IMETHOD_(nsIFormControl*) GetDefaultSubmitElement() const; - NS_IMETHOD_(PRBool) IsDefaultSubmitElement(const nsIFormControl* aControl) const; - NS_IMETHOD_(PRBool) HasSingleTextControl() const; - - // nsIRadioGroupContainer - NS_IMETHOD SetCurrentRadioButton(const nsAString& aName, - nsIDOMHTMLInputElement* aRadio); - NS_IMETHOD GetCurrentRadioButton(const nsAString& aName, - nsIDOMHTMLInputElement** aRadio); - NS_IMETHOD GetPositionInGroup(nsIDOMHTMLInputElement *aRadio, - PRInt32 *aPositionIndex, - PRInt32 *aItemsInGroup); - NS_IMETHOD GetNextRadioButton(const nsAString& aName, - const PRBool aPrevious, - nsIDOMHTMLInputElement* aFocusedRadio, - nsIDOMHTMLInputElement** aRadioOut); - NS_IMETHOD WalkRadioGroup(const nsAString& aName, nsIRadioVisitor* aVisitor, - PRBool aFlushContent); - NS_IMETHOD AddToRadioGroup(const nsAString& aName, - nsIFormControl* aRadio); - NS_IMETHOD RemoveFromRadioGroup(const nsAString& aName, - nsIFormControl* aRadio); - - // nsIContent - virtual PRBool ParseAttribute(PRInt32 aNamespaceID, - nsIAtom* aAttribute, - const nsAString& aValue, - nsAttrValue& aResult); - virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor); - virtual nsresult WillHandleEvent(nsEventChainPostVisitor& aVisitor); - virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor); - - virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, - nsIContent* aBindingParent, - PRBool aCompileEventHandlers); - virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, - PRBool aNullParent = PR_TRUE); - nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, - const nsAString& aValue, PRBool aNotify) - { - return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify); - } - virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, - nsIAtom* aPrefix, const nsAString& aValue, - PRBool aNotify); - - /** - * Forget all information about the current submission (and the fact that we - * are currently submitting at all). - */ - void ForgetCurrentSubmission(); - - virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; - - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLFormElement, - nsGenericHTMLElement) - -protected: - class RemoveElementRunnable; - friend class RemoveElementRunnable; - - class RemoveElementRunnable : public nsRunnable { - public: - RemoveElementRunnable(nsHTMLFormElement* aForm, PRBool aNotify): - mForm(aForm), mNotify(aNotify) - {} - - NS_IMETHOD Run() { - mForm->HandleDefaultSubmitRemoval(mNotify); - return NS_OK; - } - - private: - nsRefPtr mForm; - PRBool mNotify; - }; - - nsresult DoSubmitOrReset(nsEvent* aEvent, - PRInt32 aMessage); - nsresult DoReset(); - - // Async callback to handle removal of our default submit - void HandleDefaultSubmitRemoval(PRBool aNotify); - - // - // Submit Helpers - // - // - /** - * Attempt to submit (submission might be deferred) - * (called by DoSubmitOrReset) - * - * @param aPresContext the presentation context - * @param aEvent the DOM event that was passed to us for the submit - */ - nsresult DoSubmit(nsEvent* aEvent); - - /** - * Prepare the submission object (called by DoSubmit) - * - * @param aFormSubmission the submission object - * @param aEvent the DOM event that was passed to us for the submit - */ - nsresult BuildSubmission(nsCOMPtr& aFormSubmission, - nsEvent* aEvent); - /** - * Perform the submission (called by DoSubmit and FlushPendingSubmission) - * - * @param aFormSubmission the submission object - */ - nsresult SubmitSubmission(nsIFormSubmission* aFormSubmission); - /** - * Walk over the form elements and call SubmitNamesValues() on them to get - * their data pumped into the FormSubmitter. - * - * @param aFormSubmission the form submission object - * @param aSubmitElement the element that was clicked on (nsnull if none) - */ - nsresult WalkFormElements(nsIFormSubmission* aFormSubmission, - nsIContent* aSubmitElement); - - /** - * Notify any submit observers of the submit. - * - * @param aActionURL the URL being submitted to - * @param aCancelSubmit out param where submit observers can specify that the - * submit should be cancelled. - */ - nsresult NotifySubmitObservers(nsIURI* aActionURL, PRBool* aCancelSubmit, - PRBool aEarlyNotify); - - /** - * Just like ResolveName(), but takes an arg for whether to flush - */ - already_AddRefed DoResolveName(const nsAString& aName, PRBool aFlushContent); - - // - // Data members - // - /** The list of controls (form.elements as well as stuff not in elements) */ - nsRefPtr mControls; - /** The currently selected radio button of each group */ - nsInterfaceHashtable mSelectedRadioButtons; - /** Whether we are currently processing a submit event or not */ - PRPackedBool mGeneratingSubmit; - /** Whether we are currently processing a reset event or not */ - PRPackedBool mGeneratingReset; - /** Whether we are submitting currently */ - PRPackedBool mIsSubmitting; - /** Whether the submission is to be deferred in case a script triggers it */ - PRPackedBool mDeferSubmission; - /** Whether we notified NS_FORMSUBMIT_SUBJECT listeners already */ - PRPackedBool mNotifiedObservers; - /** If we notified the listeners early, what was the result? */ - PRPackedBool mNotifiedObserversResult; - /** Keep track of what the popup state was when the submit was initiated */ - PopupControlState mSubmitPopupState; - /** Keep track of whether a submission was user-initiated or not */ - PRBool mSubmitInitiatedFromUserInput; - - /** The pending submission object */ - nsCOMPtr mPendingSubmission; - /** The request currently being submitted */ - nsCOMPtr mSubmittingRequest; - /** The web progress object we are currently listening to */ - nsWeakPtr mWebProgress; - - /** The default submit element -- WEAK */ - nsIFormControl* mDefaultSubmitElement; - - /** The first submit element in mElements -- WEAK */ - nsIFormControl* mFirstSubmitInElements; - - /** The first submit element in mNotInElements -- WEAK */ - nsIFormControl* mFirstSubmitNotInElements; - -protected: - /** Detection of first form to notify observers */ - static PRBool gFirstFormSubmitted; - /** Detection of first password input to initialize the password manager */ - static PRBool gPasswordManagerInitialized; -}; - PRBool nsHTMLFormElement::gFirstFormSubmitted = PR_FALSE; PRBool nsHTMLFormElement::gPasswordManagerInitialized = PR_FALSE; @@ -396,7 +113,8 @@ public: *aResult = NS_OK; - return mElements.SafeElementAt(aIndex, nsnull); + // XXXbz this should start returning nsINode* or something! + return static_cast(mElements.SafeElementAt(aIndex, nsnull)); } virtual nsISupports* GetNamedItem(const nsAString& aName, nsresult* aResult) { @@ -405,9 +123,9 @@ public: return NamedItemInternal(aName, PR_TRUE); } - nsresult AddElementToTable(nsIFormControl* aChild, + nsresult AddElementToTable(nsGenericHTMLFormElement* aChild, const nsAString& aName); - nsresult RemoveElementFromTable(nsIFormControl* aChild, + nsresult RemoveElementFromTable(nsGenericHTMLFormElement* aChild, const nsAString& aName); nsresult IndexOfControl(nsIFormControl* aControl, PRInt32* aIndex); @@ -423,18 +141,18 @@ public: * @param aControls The list of sorted controls[out]. * @return NS_OK or NS_ERROR_OUT_OF_MEMORY. */ - nsresult GetSortedControls(nsTArray& aControls) const; + nsresult GetSortedControls(nsTArray& aControls) const; nsHTMLFormElement* mForm; // WEAK - the form owns me - nsTArray mElements; // Holds WEAK references - bug 36639 + nsTArray mElements; // Holds WEAK references - bug 36639 // This array holds on to all form controls that are not contained // in mElements (form.elements in JS, see ShouldBeInFormControl()). // This is needed to properly clean up the bi-directional references // (both weak and strong) between the form and its form controls. - nsTArray mNotInElements; // Holds WEAK references + nsTArray mNotInElements; // Holds WEAK references NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFormControlList, nsIHTMLCollection) @@ -751,18 +469,16 @@ nsHTMLFormElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, } static void -MarkOrphans(const nsTArray aArray) +MarkOrphans(const nsTArray aArray) { PRUint32 length = aArray.Length(); for (PRUint32 i = 0; i < length; ++i) { - nsCOMPtr node = do_QueryInterface(aArray[i]); - NS_ASSERTION(node, "Form control must be nsINode"); - node->SetFlags(MAYBE_ORPHAN_FORM_ELEMENT); + aArray[i]->SetFlags(MAYBE_ORPHAN_FORM_ELEMENT); } } static void -CollectOrphans(nsINode* aRemovalRoot, nsTArray aArray +CollectOrphans(nsINode* aRemovalRoot, nsTArray aArray #ifdef DEBUG , nsIDOMHTMLFormElement* aThisForm #endif @@ -771,9 +487,7 @@ CollectOrphans(nsINode* aRemovalRoot, nsTArray aArray // Walk backwards so that if we remove elements we can just keep iterating PRUint32 length = aArray.Length(); for (PRUint32 i = length; i > 0; --i) { - nsIFormControl* control = aArray[i-1]; - nsCOMPtr node = do_QueryInterface(control); - NS_ASSERTION(node, "Form control must be nsINode"); + nsGenericHTMLFormElement* node = aArray[i-1]; // Now if MAYBE_ORPHAN_FORM_ELEMENT is not set, that would mean that the // node is in fact a descendant of the form and hence should stay in the @@ -786,7 +500,7 @@ CollectOrphans(nsINode* aRemovalRoot, nsTArray aArray if (node->HasFlag(MAYBE_ORPHAN_FORM_ELEMENT)) { node->UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT); if (!nsContentUtils::ContentIsDescendantOf(node, aRemovalRoot)) { - control->ClearForm(PR_TRUE, PR_TRUE); + node->ClearForm(PR_TRUE, PR_TRUE); #ifdef DEBUG removed = PR_TRUE; #endif @@ -796,7 +510,7 @@ CollectOrphans(nsINode* aRemovalRoot, nsTArray aArray #ifdef DEBUG if (!removed) { nsCOMPtr form; - control->GetForm(getter_AddRefs(form)); + node->GetForm(getter_AddRefs(form)); NS_ASSERTION(form == aThisForm, "How did that happen?"); } #endif /* DEBUG */ @@ -964,8 +678,8 @@ nsHTMLFormElement::DoReset() // JBK walk the elements[] array instead of form frame controls - bug 34297 PRUint32 numElements = GetElementCount(); for (PRUint32 elementX = 0; (elementX < numElements); elementX++) { - nsCOMPtr controlNode; - GetElementAt(elementX, getter_AddRefs(controlNode)); + // Hold strong ref in case the reset does something weird + nsCOMPtr controlNode = GetElementAt(elementX); if (controlNode) { controlNode->Reset(); } @@ -1236,7 +950,7 @@ nsresult nsHTMLFormElement::WalkFormElements(nsIFormSubmission* aFormSubmission, nsIContent* aSubmitElement) { - nsTArray sortedControls; + nsTArray sortedControls; nsresult rv = mControls->GetSortedControls(sortedControls); NS_ENSURE_SUCCESS(rv, rv); @@ -1262,19 +976,10 @@ nsHTMLFormElement::GetElementCount() const return count; } -NS_IMETHODIMP -nsHTMLFormElement::GetElementAt(PRInt32 aIndex, - nsIFormControl** aFormControl) const +NS_IMETHODIMP_(nsIFormControl*) +nsHTMLFormElement::GetElementAt(PRInt32 aIndex) const { - // Converting to unsigned int will handle negative indices. - if (PRUint32(aIndex) >= mControls->mElements.Length()) { - *aFormControl = nsnull; - } else { - *aFormControl = mControls->mElements[aIndex]; - NS_ADDREF(*aFormControl); - } - - return NS_OK; + return mControls->mElements.SafeElementAt(aIndex, nsnull); } /** @@ -1286,21 +991,17 @@ nsHTMLFormElement::GetElementAt(PRInt32 aIndex, * > 0 if aControl1 is after aControl2, * 0 otherwise */ -static PRInt32 CompareFormControlPosition(nsIFormControl *aControl1, - nsIFormControl *aControl2, - const nsIContent* aForm) +static inline PRInt32 +CompareFormControlPosition(nsGenericHTMLFormElement *aControl1, + nsGenericHTMLFormElement *aControl2, + const nsIContent* aForm) { NS_ASSERTION(aControl1 != aControl2, "Comparing a form control to itself"); - nsCOMPtr content1 = do_QueryInterface(aControl1); - nsCOMPtr content2 = do_QueryInterface(aControl2); - - NS_ASSERTION(content1 && content2, - "We should be able to QI to nsIContent here!"); - NS_ASSERTION(content1->GetParent() && content2->GetParent(), + NS_ASSERTION(aControl1->GetParent() && aControl2->GetParent(), "Form controls should always have parents"); - return nsLayoutUtils::CompareTreePosition(content1, content2, aForm); + return nsLayoutUtils::CompareTreePosition(aControl1, aControl2, aForm); } #ifdef DEBUG @@ -1312,7 +1013,7 @@ static PRInt32 CompareFormControlPosition(nsIFormControl *aControl1, * @param aForm Parent form of the controls. */ static void -AssertDocumentOrder(const nsTArray& aControls, +AssertDocumentOrder(const nsTArray& aControls, nsIContent* aForm) { // Only iterate if aControls is not empty, since otherwise @@ -1328,29 +1029,23 @@ AssertDocumentOrder(const nsTArray& aControls, } #endif -NS_IMETHODIMP -nsHTMLFormElement::AddElement(nsIFormControl* aChild, +nsresult +nsHTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild, PRBool aNotify) { -#ifdef DEBUG - { - nsCOMPtr content = do_QueryInterface(aChild); - NS_ASSERTION(content->GetParent(), - "Form control should have a parent"); - } -#endif + NS_ASSERTION(aChild->GetParent(), "Form control should have a parent"); // Determine whether to add the new element to the elements or // the not-in-elements list. PRBool childInElements = ShouldBeInElements(aChild); - nsTArray& controlList = childInElements ? + nsTArray& controlList = childInElements ? mControls->mElements : mControls->mNotInElements; NS_ASSERTION(controlList.IndexOf(aChild) == controlList.NoIndex, "Form control already in form"); PRUint32 count = controlList.Length(); - nsCOMPtr element; + nsGenericHTMLFormElement* element; // Optimize most common case where we insert at the end. PRBool lastElement = PR_FALSE; @@ -1396,7 +1091,8 @@ nsHTMLFormElement::AddElement(nsIFormControl* aChild, // PRInt32 type = aChild->GetType(); if (type == NS_FORM_INPUT_RADIO) { - nsCOMPtr radio = do_QueryInterface(aChild); + nsCOMPtr radio; + CallQueryInterface(aChild, getter_AddRefs(radio)); nsresult rv = radio->AddedToRadioGroup(); NS_ENSURE_SUCCESS(rv, rv); } @@ -1418,7 +1114,7 @@ nsHTMLFormElement::AddElement(nsIFormControl* aChild, // Update mDefaultSubmitElement, mFirstSubmitInElements, // mFirstSubmitNotInElements. - nsIFormControl** firstSubmitSlot = + nsGenericHTMLFormElement** firstSubmitSlot = childInElements ? &mFirstSubmitInElements : &mFirstSubmitNotInElements; // The new child is the new first submit in its list if the firstSubmitSlot @@ -1469,16 +1165,16 @@ nsHTMLFormElement::AddElement(nsIFormControl* aChild, return NS_OK; } -NS_IMETHODIMP -nsHTMLFormElement::AddElementToTable(nsIFormControl* aChild, +nsresult +nsHTMLFormElement::AddElementToTable(nsGenericHTMLFormElement* aChild, const nsAString& aName) { return mControls->AddElementToTable(aChild, aName); } -NS_IMETHODIMP -nsHTMLFormElement::RemoveElement(nsIFormControl* aChild, +nsresult +nsHTMLFormElement::RemoveElement(nsGenericHTMLFormElement* aChild, PRBool aNotify) { // @@ -1486,7 +1182,8 @@ nsHTMLFormElement::RemoveElement(nsIFormControl* aChild, // nsresult rv = NS_OK; if (aChild->GetType() == NS_FORM_INPUT_RADIO) { - nsCOMPtr radio = do_QueryInterface(aChild); + nsCOMPtr radio; + CallQueryInterface(aChild, getter_AddRefs(radio)); rv = radio->WillRemoveFromRadioGroup(); NS_ENSURE_SUCCESS(rv, rv); } @@ -1494,7 +1191,7 @@ nsHTMLFormElement::RemoveElement(nsIFormControl* aChild, // Determine whether to remove the child from the elements list // or the not in elements list. PRBool childInElements = ShouldBeInElements(aChild); - nsTArray& controls = childInElements ? + nsTArray& controls = childInElements ? mControls->mElements : mControls->mNotInElements; // Find the index of the child. This will be used later if necessary @@ -1505,7 +1202,7 @@ nsHTMLFormElement::RemoveElement(nsIFormControl* aChild, controls.RemoveElementAt(index); // Update our mFirstSubmit* values. - nsIFormControl** firstSubmitSlot = + nsGenericHTMLFormElement** firstSubmitSlot = childInElements ? &mFirstSubmitInElements : &mFirstSubmitNotInElements; if (aChild == *firstSubmitSlot) { *firstSubmitSlot = nsnull; @@ -1513,7 +1210,7 @@ nsHTMLFormElement::RemoveElement(nsIFormControl* aChild, // We are removing the first submit in this list, find the new first submit PRUint32 length = controls.Length(); for (PRUint32 i = index; i < length; ++i) { - nsIFormControl* currentControl = controls[i]; + nsGenericHTMLFormElement* currentControl = controls[i]; if (currentControl->IsSubmitControl()) { *firstSubmitSlot = currentControl; break; @@ -1567,15 +1264,14 @@ nsHTMLFormElement::HandleDefaultSubmitRemoval(PRBool aNotify) nsIDocument* document = GetCurrentDoc(); if (document) { MOZ_AUTO_DOC_UPDATE(document, UPDATE_CONTENT_STATE, PR_TRUE); - nsCOMPtr newElement(do_QueryInterface(mDefaultSubmitElement)); - document->ContentStatesChanged(newElement, nsnull, + document->ContentStatesChanged(mDefaultSubmitElement, nsnull, NS_EVENT_STATE_DEFAULT); } } } -NS_IMETHODIMP -nsHTMLFormElement::RemoveElementFromTable(nsIFormControl* aElement, +nsresult +nsHTMLFormElement::RemoveElementFromTable(nsGenericHTMLFormElement* aElement, const nsAString& aName) { return mControls->RemoveElementFromTable(aElement, aName); @@ -1596,7 +1292,7 @@ nsHTMLFormElement::DoResolveName(const nsAString& aName, return result; } -NS_IMETHODIMP +void nsHTMLFormElement::OnSubmitClickBegin() { mDeferSubmission = PR_TRUE; @@ -1609,7 +1305,7 @@ nsHTMLFormElement::OnSubmitClickBegin() rv = GetActionURL(getter_AddRefs(actionURI)); if (NS_FAILED(rv) || !actionURI) - return NS_OK; + return; // // Notify observers of submit @@ -1620,24 +1316,21 @@ nsHTMLFormElement::OnSubmitClickBegin() mNotifiedObservers = PR_TRUE; mNotifiedObserversResult = cancelSubmit; } - - return NS_OK; } -NS_IMETHODIMP +void nsHTMLFormElement::OnSubmitClickEnd() { mDeferSubmission = PR_FALSE; - return NS_OK; } -NS_IMETHODIMP +void nsHTMLFormElement::FlushPendingSubmission() { nsCOMPtr kunkFuDeathGrip(mPendingSubmission); if (!mPendingSubmission) { - return NS_OK; + return; } // @@ -1647,18 +1340,16 @@ nsHTMLFormElement::FlushPendingSubmission() // now delete the pending submission object mPendingSubmission = nsnull; - return NS_OK; } -NS_IMETHODIMP +void nsHTMLFormElement::ForgetPendingSubmission() { // just delete the pending submission mPendingSubmission = nsnull; - return NS_OK; } -NS_IMETHODIMP +nsresult nsHTMLFormElement::GetActionURL(nsIURI** aActionURL) { nsresult rv = NS_OK; @@ -1736,12 +1427,6 @@ nsHTMLFormElement::GetActionURL(nsIURI** aActionURL) return rv; } -NS_IMETHODIMP -nsHTMLFormElement::GetSortedControls(nsTArray& aControls) const -{ - return mControls->GetSortedControls(aControls); -} - NS_IMETHODIMP_(nsIFormControl*) nsHTMLFormElement::GetDefaultSubmitElement() const { @@ -1752,7 +1437,7 @@ nsHTMLFormElement::GetDefaultSubmitElement() const return mDefaultSubmitElement; } -NS_IMETHODIMP_(PRBool) +PRBool nsHTMLFormElement::IsDefaultSubmitElement(const nsIFormControl* aControl) const { NS_PRECONDITION(aControl, "Unexpected call"); @@ -1787,7 +1472,7 @@ nsHTMLFormElement::IsDefaultSubmitElement(const nsIFormControl* aControl) const return aControl == defaultSubmit; } -NS_IMETHODIMP_(PRBool) +PRBool nsHTMLFormElement::HasSingleTextControl() const { // Input text controls are always in the elements list. @@ -1938,12 +1623,8 @@ nsHTMLFormElement::GetPositionInGroup(nsIDOMHTMLInputElement *aRadio, nsCOMPtr itemWithName; itemWithName = ResolveName(name); NS_ENSURE_TRUE(itemWithName, NS_ERROR_FAILURE); - nsCOMPtr radioNodeList(do_QueryInterface(itemWithName)); + nsCOMPtr radioGroup(do_QueryInterface(itemWithName)); - // XXX If ResolveName could return an nsContentList instead then we - // could get an nsContentList instead of using this hacky upcast - nsBaseContentList *radioGroup = - static_cast((nsIDOMNodeList *)radioNodeList); NS_ASSERTION(radioGroup, "No such radio group in this container"); if (!radioGroup) { return NS_OK; @@ -1951,7 +1632,7 @@ nsHTMLFormElement::GetPositionInGroup(nsIDOMHTMLInputElement *aRadio, nsCOMPtr currentRadioNode(do_QueryInterface(aRadio)); NS_ASSERTION(currentRadioNode, "No nsIContent for current radio button"); - *aPositionIndex = radioGroup->IndexOf(currentRadioNode, PR_TRUE); + *aPositionIndex = radioGroup->IndexOf(currentRadioNode); NS_ASSERTION(*aPositionIndex >= 0, "Radio button not found in its own group"); PRUint32 itemsInGroup; radioGroup->GetLength(&itemsInGroup); @@ -1979,20 +1660,15 @@ nsHTMLFormElement::GetNextRadioButton(const nsAString& aName, } nsCOMPtr itemWithName = ResolveName(aName); - nsCOMPtr radioNodeList(do_QueryInterface(itemWithName)); + nsCOMPtr radioGroup(do_QueryInterface(itemWithName)); - // XXX If ResolveName could return an nsContentList instead then we - // could get an nsContentList instead of using this hacky upcast - - nsBaseContentList *radioGroup = - static_cast((nsIDOMNodeList *)radioNodeList); if (!radioGroup) { return NS_ERROR_FAILURE; } nsCOMPtr currentRadioNode(do_QueryInterface(currentRadio)); NS_ASSERTION(currentRadioNode, "No nsIContent for current radio button"); - PRInt32 index = radioGroup->IndexOf(currentRadioNode, PR_TRUE); + PRInt32 index = radioGroup->IndexOf(currentRadioNode); if (index < 0) { return NS_ERROR_FAILURE; } @@ -2001,7 +1677,6 @@ nsHTMLFormElement::GetNextRadioButton(const nsAString& aName, radioGroup->GetLength(&numRadios); PRBool disabled = PR_TRUE; nsCOMPtr radio; - nsCOMPtr radioDOMNode; nsCOMPtr formControl; do { @@ -2013,11 +1688,11 @@ nsHTMLFormElement::GetNextRadioButton(const nsAString& aName, else if (++index >= (PRInt32)numRadios) { index = 0; } - radioGroup->Item(index, getter_AddRefs(radioDOMNode)); - radio = do_QueryInterface(radioDOMNode); + radio = do_QueryInterface(radioGroup->GetNodeAt(index)); if (!radio) continue; + // XXXbz why is this formControl check needed, exactly? formControl = do_QueryInterface(radio); if (!formControl || formControl->GetType() != NS_FORM_INPUT_RADIO) continue; @@ -2046,7 +1721,7 @@ nsHTMLFormElement::WalkRadioGroup(const nsAString& aName, nsCOMPtr control; PRUint32 len = GetElementCount(); for (PRUint32 i=0; iGetType() == NS_FORM_INPUT_RADIO) { nsCOMPtr controlContent(do_QueryInterface(control)); if (controlContent) { @@ -2292,7 +1967,7 @@ nsFormControlList::NamedItemInternal(const nsAString& aName, } nsresult -nsFormControlList::AddElementToTable(nsIFormControl* aChild, +nsFormControlList::AddElementToTable(nsGenericHTMLFormElement* aChild, const nsAString& aName) { if (!ShouldBeInElements(aChild)) { @@ -2304,20 +1979,19 @@ nsFormControlList::AddElementToTable(nsIFormControl* aChild, if (!supports) { // No entry found, add the form control - nsCOMPtr child(do_QueryInterface(aChild)); - - NS_ENSURE_TRUE( mNameLookupTable.Put(aName, child), NS_ERROR_FAILURE ); + NS_ENSURE_TRUE( mNameLookupTable.Put(aName, + NS_ISUPPORTS_CAST(nsIContent*, aChild)), + NS_ERROR_FAILURE ); } else { // Found something in the hash, check its type nsCOMPtr content(do_QueryInterface(supports)); - nsCOMPtr newChild(do_QueryInterface(aChild)); if (content) { // Check if the new content is the same as the one we found in the // hash, if it is then we leave it in the hash as it is, this will // happen if a form control has both a name and an id with the same // value - if (content == newChild) { + if (content == aChild) { return NS_OK; } @@ -2329,10 +2003,10 @@ nsFormControlList::AddElementToTable(nsIFormControl* aChild, NS_ASSERTION(content->GetParent(), "Item in list without parent"); // Determine the ordering between the new and old element. - PRBool newFirst = nsContentUtils::PositionIsBefore(newChild, content); + PRBool newFirst = nsContentUtils::PositionIsBefore(aChild, content); - list->AppendElement(newFirst ? newChild : content); - list->AppendElement(newFirst ? content : newChild); + list->AppendElement(newFirst ? aChild : content); + list->AppendElement(newFirst ? content : aChild); nsCOMPtr listSupports = @@ -2353,8 +2027,8 @@ nsFormControlList::AddElementToTable(nsIFormControl* aChild, NS_ASSERTION(list->Length() > 1, "List should have been converted back to a single element"); - if(nsContentUtils::PositionIsBefore(list->GetNodeAt(list->Length() - 1), newChild)) { - list->AppendElement(newChild); + if(nsContentUtils::PositionIsBefore(list->GetNodeAt(list->Length() - 1), aChild)) { + list->AppendElement(aChild); return NS_OK; } @@ -2368,13 +2042,13 @@ nsFormControlList::AddElementToTable(nsIFormControl* aChild, while (last != first) { mid = (first + last) / 2; - if (nsContentUtils::PositionIsBefore(newChild, list->GetNodeAt(mid))) + if (nsContentUtils::PositionIsBefore(aChild, list->GetNodeAt(mid))) last = mid; else first = mid + 1; } - list->InsertElementAt(newChild, first); + list->InsertElementAt(aChild, first); } } @@ -2395,18 +2069,13 @@ nsFormControlList::IndexOfControl(nsIFormControl* aControl, } nsresult -nsFormControlList::RemoveElementFromTable(nsIFormControl* aChild, +nsFormControlList::RemoveElementFromTable(nsGenericHTMLFormElement* aChild, const nsAString& aName) { if (!ShouldBeInElements(aChild)) { return NS_OK; } - nsCOMPtr content = do_QueryInterface(aChild); - if (!content) { - return NS_OK; - } - nsCOMPtr supports; if (!mNameLookupTable.Get(aName, getter_AddRefs(supports))) @@ -2431,7 +2100,7 @@ nsFormControlList::RemoveElementFromTable(nsIFormControl* aChild, nsBaseContentList *list = static_cast ((nsIDOMNodeList *)nodeList.get()); - list->RemoveElement(content); + list->RemoveElement(aChild); PRUint32 length = 0; list->GetLength(&length); @@ -2443,12 +2112,9 @@ nsFormControlList::RemoveElementFromTable(nsIFormControl* aChild, } else if (length == 1) { // Only one element left, replace the list in the hash with the // single element. - nsCOMPtr node; - list->Item(0, getter_AddRefs(node)); - + nsIContent* node = list->GetNodeAt(0); if (node) { - nsCOMPtr tmp(do_QueryInterface(node)); - NS_ENSURE_TRUE(mNameLookupTable.Put(aName, tmp),NS_ERROR_FAILURE); + NS_ENSURE_TRUE(mNameLookupTable.Put(aName, node),NS_ERROR_FAILURE); } } @@ -2456,7 +2122,7 @@ nsFormControlList::RemoveElementFromTable(nsIFormControl* aChild, } nsresult -nsFormControlList::GetSortedControls(nsTArray& aControls) const +nsFormControlList::GetSortedControls(nsTArray& aControls) const { #ifdef DEBUG AssertDocumentOrder(mElements, mForm); @@ -2507,7 +2173,7 @@ nsFormControlList::GetSortedControls(nsTArray& aControls) const "Should have remaining elements"); // Determine which of the two elements should be ordered // first and add it to the end of the list. - nsIFormControl* elementToAdd; + nsGenericHTMLFormElement* elementToAdd; if (CompareFormControlPosition(mElements[elementsIdx], mNotInElements[notInElementsIdx], mForm) < 0) { diff --git a/content/html/content/src/nsHTMLFormElement.h b/content/html/content/src/nsHTMLFormElement.h new file mode 100644 index 000000000000..b38e391bfc8a --- /dev/null +++ b/content/html/content/src/nsHTMLFormElement.h @@ -0,0 +1,394 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "nsCOMPtr.h" +#include "nsIForm.h" +#include "nsIFormControl.h" +#include "nsIFormSubmission.h" +#include "nsGenericHTMLElement.h" +#include "nsIDOMHTMLFormElement.h" +#include "nsIDOMNSHTMLFormElement.h" +#include "nsIWebProgressListener.h" +#include "nsIRadioGroupContainer.h" +#include "nsIURI.h" +#include "nsIWeakReferenceUtils.h" +#include "nsPIDOMWindow.h" +#include "nsUnicharUtils.h" +#include "nsThreadUtils.h" + +class nsFormControlList; + +/** + * hashkey wrapper using nsAString KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class nsStringCaseInsensitiveHashKey : public PLDHashEntryHdr +{ +public: + typedef const nsAString& KeyType; + typedef const nsAString* KeyTypePointer; + nsStringCaseInsensitiveHashKey(KeyTypePointer aStr) : mStr(*aStr) { } //take it easy just deal HashKey + nsStringCaseInsensitiveHashKey(const nsStringCaseInsensitiveHashKey& toCopy) : mStr(toCopy.mStr) { } + ~nsStringCaseInsensitiveHashKey() { } + + KeyType GetKey() const { return mStr; } + PRBool KeyEquals(const KeyTypePointer aKey) const + { + return mStr.Equals(*aKey,nsCaseInsensitiveStringComparator()); + } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(const KeyTypePointer aKey) + { + nsAutoString tmKey(*aKey); + ToLowerCase(tmKey); + return HashString(tmKey); + } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const nsString mStr; +}; + +class nsHTMLFormElement : public nsGenericHTMLElement, + public nsIDOMHTMLFormElement, + public nsIDOMNSHTMLFormElement, + public nsIWebProgressListener, + public nsIForm, + public nsIRadioGroupContainer +{ +public: + nsHTMLFormElement(nsINodeInfo *aNodeInfo); + virtual ~nsHTMLFormElement(); + + nsresult Init(); + + // nsISupports + NS_DECL_ISUPPORTS_INHERITED + + // nsIDOMNode + NS_FORWARD_NSIDOMNODE(nsGenericHTMLElement::) + + // nsIDOMElement + NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::) + + // nsIDOMHTMLElement + NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::) + + // nsIDOMHTMLFormElement + NS_DECL_NSIDOMHTMLFORMELEMENT + + // nsIDOMNSHTMLFormElement + NS_DECL_NSIDOMNSHTMLFORMELEMENT + + // nsIWebProgressListener + NS_DECL_NSIWEBPROGRESSLISTENER + + // nsIForm + NS_IMETHOD_(nsIFormControl*) GetElementAt(PRInt32 aIndex) const; + NS_IMETHOD_(PRUint32) GetElementCount() const; + NS_IMETHOD_(already_AddRefed) ResolveName(const nsAString& aName); + NS_IMETHOD_(PRInt32) IndexOfControl(nsIFormControl* aControl); + NS_IMETHOD_(nsIFormControl*) GetDefaultSubmitElement() const; + + // nsIRadioGroupContainer + NS_IMETHOD SetCurrentRadioButton(const nsAString& aName, + nsIDOMHTMLInputElement* aRadio); + NS_IMETHOD GetCurrentRadioButton(const nsAString& aName, + nsIDOMHTMLInputElement** aRadio); + NS_IMETHOD GetPositionInGroup(nsIDOMHTMLInputElement *aRadio, + PRInt32 *aPositionIndex, + PRInt32 *aItemsInGroup); + NS_IMETHOD GetNextRadioButton(const nsAString& aName, + const PRBool aPrevious, + nsIDOMHTMLInputElement* aFocusedRadio, + nsIDOMHTMLInputElement** aRadioOut); + NS_IMETHOD WalkRadioGroup(const nsAString& aName, nsIRadioVisitor* aVisitor, + PRBool aFlushContent); + NS_IMETHOD AddToRadioGroup(const nsAString& aName, + nsIFormControl* aRadio); + NS_IMETHOD RemoveFromRadioGroup(const nsAString& aName, + nsIFormControl* aRadio); + + // nsIContent + virtual PRBool ParseAttribute(PRInt32 aNamespaceID, + nsIAtom* aAttribute, + const nsAString& aValue, + nsAttrValue& aResult); + virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor); + virtual nsresult WillHandleEvent(nsEventChainPostVisitor& aVisitor); + virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor); + + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); + nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, + const nsAString& aValue, PRBool aNotify) + { + return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify); + } + virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, + nsIAtom* aPrefix, const nsAString& aValue, + PRBool aNotify); + + /** + * Forget all information about the current submission (and the fact that we + * are currently submitting at all). + */ + void ForgetCurrentSubmission(); + + virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; + + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLFormElement, + nsGenericHTMLElement) + + /** + * Remove an element from this form's list of elements + * + * @param aElement the element to remove + * @param aNotify If true, send nsIDocumentObserver notifications as needed. + * @return NS_OK if the element was successfully removed. + */ + nsresult RemoveElement(nsGenericHTMLFormElement* aElement, PRBool aNotify); + + /** + * Remove an element from the lookup table mainted by the form. + * We can't fold this method into RemoveElement() because when + * RemoveElement() is called it doesn't know if the element is + * removed because the id attribute has changed, or bacause the + * name attribute has changed. + * + * @param aElement the element to remove + * @param aName the name or id of the element to remove + * @return NS_OK if the element was successfully removed. + */ + nsresult RemoveElementFromTable(nsGenericHTMLFormElement* aElement, + const nsAString& aName); + /** + * Add an element to end of this form's list of elements + * + * @param aElement the element to add + * @param aNotify If true, send nsIDocumentObserver notifications as needed. + * @return NS_OK if the element was successfully added + */ + nsresult AddElement(nsGenericHTMLFormElement* aElement, PRBool aNotify); + + /** + * 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. + */ + nsresult AddElementToTable(nsGenericHTMLFormElement* aChild, + const nsAString& aName); + /** + * Return whether there is one and only one input text control. + * + * @return Whether there is exactly one input text control. + */ + PRBool HasSingleTextControl() const; + + /** + * Check whether a given nsIFormControl is the default submit + * element. This is different from just comparing to + * GetDefaultSubmitElement() in certain situations inside an update + * when GetDefaultSubmitElement() might not be up to date. aControl + * is expected to not be null. + */ + PRBool IsDefaultSubmitElement(const nsIFormControl* aControl) const; + + /** + * Flag the form to know that a button or image triggered scripted form + * submission. In that case the form will defer the submission until the + * script handler returns and the return value is known. + */ + void OnSubmitClickBegin(); + void OnSubmitClickEnd(); + +protected: + class RemoveElementRunnable; + friend class RemoveElementRunnable; + + class RemoveElementRunnable : public nsRunnable { + public: + RemoveElementRunnable(nsHTMLFormElement* aForm, PRBool aNotify): + mForm(aForm), mNotify(aNotify) + {} + + NS_IMETHOD Run() { + mForm->HandleDefaultSubmitRemoval(mNotify); + return NS_OK; + } + + private: + nsRefPtr mForm; + PRBool mNotify; + }; + + nsresult DoSubmitOrReset(nsEvent* aEvent, + PRInt32 aMessage); + nsresult DoReset(); + + // Async callback to handle removal of our default submit + void HandleDefaultSubmitRemoval(PRBool aNotify); + + // + // Submit Helpers + // + // + /** + * Attempt to submit (submission might be deferred) + * (called by DoSubmitOrReset) + * + * @param aPresContext the presentation context + * @param aEvent the DOM event that was passed to us for the submit + */ + nsresult DoSubmit(nsEvent* aEvent); + + /** + * Prepare the submission object (called by DoSubmit) + * + * @param aFormSubmission the submission object + * @param aEvent the DOM event that was passed to us for the submit + */ + nsresult BuildSubmission(nsCOMPtr& aFormSubmission, + nsEvent* aEvent); + /** + * Perform the submission (called by DoSubmit and FlushPendingSubmission) + * + * @param aFormSubmission the submission object + */ + nsresult SubmitSubmission(nsIFormSubmission* aFormSubmission); + /** + * Walk over the form elements and call SubmitNamesValues() on them to get + * their data pumped into the FormSubmitter. + * + * @param aFormSubmission the form submission object + * @param aSubmitElement the element that was clicked on (nsnull if none) + */ + nsresult WalkFormElements(nsIFormSubmission* aFormSubmission, + nsIContent* aSubmitElement); + + /** + * Notify any submit observers of the submit. + * + * @param aActionURL the URL being submitted to + * @param aCancelSubmit out param where submit observers can specify that the + * submit should be cancelled. + */ + nsresult NotifySubmitObservers(nsIURI* aActionURL, PRBool* aCancelSubmit, + PRBool aEarlyNotify); + + /** + * Just like ResolveName(), but takes an arg for whether to flush + */ + already_AddRefed DoResolveName(const nsAString& aName, PRBool aFlushContent); + + /** + * Get the full URL to submit to. Do not submit if the returned URL is null. + * + * @param aActionURL the full, unadulterated URL you'll be submitting to [OUT] + */ + nsresult GetActionURL(nsIURI** aActionURL); + +public: + /** + * Flush a possible pending submission. If there was a scripted submission + * triggered by a button or image, the submission was defered. This method + * forces the pending submission to be submitted. (happens when the handler + * returns false or there is an action/target change in the script) + */ + void FlushPendingSubmission(); +protected: + /** + * Forget a possible pending submission. Same as above but this time we + * get rid of the pending submission because the handler returned true + * so we will rebuild the submission with the name/value of the triggering + * element + */ + void ForgetPendingSubmission(); + + // + // Data members + // + /** The list of controls (form.elements as well as stuff not in elements) */ + nsRefPtr mControls; + /** The currently selected radio button of each group */ + nsInterfaceHashtable mSelectedRadioButtons; + /** Whether we are currently processing a submit event or not */ + PRPackedBool mGeneratingSubmit; + /** Whether we are currently processing a reset event or not */ + PRPackedBool mGeneratingReset; + /** Whether we are submitting currently */ + PRPackedBool mIsSubmitting; + /** Whether the submission is to be deferred in case a script triggers it */ + PRPackedBool mDeferSubmission; + /** Whether we notified NS_FORMSUBMIT_SUBJECT listeners already */ + PRPackedBool mNotifiedObservers; + /** If we notified the listeners early, what was the result? */ + PRPackedBool mNotifiedObserversResult; + /** Keep track of what the popup state was when the submit was initiated */ + PopupControlState mSubmitPopupState; + /** Keep track of whether a submission was user-initiated or not */ + PRBool mSubmitInitiatedFromUserInput; + + /** The pending submission object */ + nsCOMPtr mPendingSubmission; + /** The request currently being submitted */ + nsCOMPtr mSubmittingRequest; + /** The web progress object we are currently listening to */ + nsWeakPtr mWebProgress; + + /** The default submit element -- WEAK */ + nsGenericHTMLFormElement* mDefaultSubmitElement; + + /** The first submit element in mElements -- WEAK */ + nsGenericHTMLFormElement* mFirstSubmitInElements; + + /** The first submit element in mNotInElements -- WEAK */ + nsGenericHTMLFormElement* mFirstSubmitNotInElements; + +protected: + /** Detection of first form to notify observers */ + static PRBool gFirstFormSubmitted; + /** Detection of first password input to initialize the password manager */ + static PRBool gPasswordManagerInitialized; +}; diff --git a/content/html/content/src/nsHTMLInputElement.cpp b/content/html/content/src/nsHTMLInputElement.cpp index 6beb2e516b30..c85b98106caa 100644 --- a/content/html/content/src/nsHTMLInputElement.cpp +++ b/content/html/content/src/nsHTMLInputElement.cpp @@ -115,6 +115,7 @@ #include "nsIDOMWindowInternal.h" #include "mozAutoDocUpdate.h" +#include "nsHTMLFormElement.h" // XXX align=left, hspace, vspace, border? other nav4 attrs @@ -1341,10 +1342,11 @@ nsHTMLInputElement::MaybeSubmitForm(nsPresContext* aPresContext) shell->HandleDOMEventWithTarget(submitContent, &event, &status); } else if (mForm->HasSingleTextControl()) { // If there's only one text control, just submit the form - nsCOMPtr form = do_QueryInterface(mForm); + // Hold strong ref across the event + nsRefPtr form(mForm); nsFormEvent event(PR_TRUE, NS_FORM_SUBMIT); nsEventStatus status = nsEventStatus_eIgnore; - shell->HandleDOMEventWithTarget(form, &event, &status); + shell->HandleDOMEventWithTarget(mForm, &event, &status); } return NS_OK; @@ -2050,8 +2052,9 @@ nsHTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor) // handling the event the pres context will return a null // pres shell. See bug 125624. if (presShell) { - nsCOMPtr form(do_QueryInterface(mForm)); - presShell->HandleDOMEventWithTarget(form, &event, &status); + // Hold a strong ref while dispatching + nsRefPtr form(mForm); + presShell->HandleDOMEventWithTarget(mForm, &event, &status); } } break; diff --git a/content/html/content/src/nsHTMLSharedElement.cpp b/content/html/content/src/nsHTMLSharedElement.cpp index e5c07438a9a1..76de6488c59c 100644 --- a/content/html/content/src/nsHTMLSharedElement.cpp +++ b/content/html/content/src/nsHTMLSharedElement.cpp @@ -48,6 +48,7 @@ #include "nsRuleData.h" #include "nsMappedAttributes.h" #include "nsNetUtil.h" +#include "nsHTMLFormElement.h" // XXX nav4 has type= start= (same as OL/UL) extern nsAttrValue::EnumTable kListTypeTable[]; @@ -203,7 +204,7 @@ NS_IMPL_INT_ATTR(nsHTMLSharedElement, Size, size) NS_IMETHODIMP nsHTMLSharedElement::GetForm(nsIDOMHTMLFormElement** aForm) { - *aForm = FindForm().get(); + NS_IF_ADDREF(*aForm = FindForm()); return NS_OK; } diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index c7434086aa84..57a59565250f 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -9207,8 +9207,7 @@ nsHTMLFormElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper, PRInt32 n = GetArrayIndexFromId(cx, id); if (n >= 0) { - nsCOMPtr control; - form->GetElementAt(n, getter_AddRefs(control)); + nsIFormControl* control = form->GetElementAt(n); if (control) { nsresult rv = WrapNative(cx, obj, control, PR_TRUE, vp); @@ -9256,8 +9255,7 @@ nsHTMLFormElementSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, PRUint32 count = form->GetElementCount(); if ((PRUint32)index < count) { - nsCOMPtr controlNode; - form->GetElementAt(index, getter_AddRefs(controlNode)); + nsIFormControl* controlNode = form->GetElementAt(index); NS_ENSURE_TRUE(controlNode, NS_ERROR_FAILURE); nsCOMPtr domElement = do_QueryInterface(controlNode);