LCOV - code coverage report
Current view: directory - content/html/content/src - nsHTMLFormElement.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 978 4 0.4 %
Date: 2012-06-02 Functions: 127 3 2.4 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Communicator client code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      26                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : #include "nsHTMLFormElement.h"
      38                 : #include "nsIHTMLDocument.h"
      39                 : #include "nsIDOMEventTarget.h"
      40                 : #include "nsEventStateManager.h"
      41                 : #include "nsEventStates.h"
      42                 : #include "nsGkAtoms.h"
      43                 : #include "nsStyleConsts.h"
      44                 : #include "nsPresContext.h"
      45                 : #include "nsIDocument.h"
      46                 : #include "nsIFrame.h"
      47                 : #include "nsIFormControlFrame.h"
      48                 : #include "nsDOMError.h"
      49                 : #include "nsContentUtils.h"
      50                 : #include "nsInterfaceHashtable.h"
      51                 : #include "nsContentList.h"
      52                 : #include "nsGUIEvent.h"
      53                 : #include "nsCOMArray.h"
      54                 : #include "nsAutoPtr.h"
      55                 : #include "nsTArray.h"
      56                 : #include "nsIMutableArray.h"
      57                 : 
      58                 : // form submission
      59                 : #include "nsIFormSubmitObserver.h"
      60                 : #include "nsIObserverService.h"
      61                 : #include "nsICategoryManager.h"
      62                 : #include "nsCategoryManagerUtils.h"
      63                 : #include "nsISimpleEnumerator.h"
      64                 : #include "nsRange.h"
      65                 : #include "nsIScriptSecurityManager.h"
      66                 : #include "nsNetUtil.h"
      67                 : #include "nsIWebProgress.h"
      68                 : #include "nsIDocShell.h"
      69                 : #include "nsFormData.h"
      70                 : #include "nsFormSubmissionConstants.h"
      71                 : 
      72                 : // radio buttons
      73                 : #include "nsIDOMHTMLInputElement.h"
      74                 : #include "nsHTMLInputElement.h"
      75                 : #include "nsIRadioVisitor.h"
      76                 : 
      77                 : #include "nsLayoutUtils.h"
      78                 : 
      79                 : #include "nsEventDispatcher.h"
      80                 : 
      81                 : #include "mozAutoDocUpdate.h"
      82                 : #include "nsIHTMLCollection.h"
      83                 : 
      84                 : #include "nsIConstraintValidation.h"
      85                 : 
      86                 : #include "nsIDOMHTMLButtonElement.h"
      87                 : #include "dombindings.h"
      88                 : 
      89                 : using namespace mozilla::dom;
      90                 : 
      91                 : static const int NS_FORM_CONTROL_LIST_HASHTABLE_SIZE = 16;
      92                 : 
      93                 : static const PRUint8 NS_FORM_AUTOCOMPLETE_ON  = 1;
      94                 : static const PRUint8 NS_FORM_AUTOCOMPLETE_OFF = 0;
      95                 : 
      96                 : static const nsAttrValue::EnumTable kFormAutocompleteTable[] = {
      97                 :   { "on",  NS_FORM_AUTOCOMPLETE_ON },
      98                 :   { "off", NS_FORM_AUTOCOMPLETE_OFF },
      99                 :   { 0 }
     100                 : };
     101                 : // Default autocomplete value is 'on'.
     102                 : static const nsAttrValue::EnumTable* kFormDefaultAutocomplete = &kFormAutocompleteTable[0];
     103                 : 
     104                 : // nsHTMLFormElement
     105                 : 
     106                 : bool nsHTMLFormElement::gFirstFormSubmitted = false;
     107                 : bool nsHTMLFormElement::gPasswordManagerInitialized = false;
     108                 : 
     109                 : 
     110                 : // nsFormControlList
     111                 : class nsFormControlList : public nsIHTMLCollection,
     112                 :                           public nsWrapperCache
     113                 : {
     114                 : public:
     115                 :   nsFormControlList(nsHTMLFormElement* aForm);
     116                 :   virtual ~nsFormControlList();
     117                 : 
     118                 :   nsresult Init();
     119                 : 
     120                 :   void DropFormReference();
     121                 : 
     122               0 :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     123                 : 
     124                 :   // nsIDOMHTMLCollection interface
     125                 :   NS_DECL_NSIDOMHTMLCOLLECTION
     126                 : 
     127               0 :   virtual nsINode* GetParentObject()
     128                 :   {
     129               0 :     return mForm;
     130                 :   }
     131                 : 
     132                 :   nsresult AddElementToTable(nsGenericHTMLFormElement* aChild,
     133                 :                              const nsAString& aName);
     134                 :   nsresult RemoveElementFromTable(nsGenericHTMLFormElement* aChild,
     135                 :                                   const nsAString& aName);
     136                 :   nsresult IndexOfControl(nsIFormControl* aControl,
     137                 :                           PRInt32* aIndex);
     138                 : 
     139                 :   nsISupports* NamedItemInternal(const nsAString& aName, bool aFlushContent);
     140                 :   
     141                 :   /**
     142                 :    * Create a sorted list of form control elements. This list is sorted
     143                 :    * in document order and contains the controls in the mElements and
     144                 :    * mNotInElements list. This function does not add references to the
     145                 :    * elements.
     146                 :    *
     147                 :    * @param aControls The list of sorted controls[out].
     148                 :    * @return NS_OK or NS_ERROR_OUT_OF_MEMORY.
     149                 :    */
     150                 :   nsresult GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aControls) const;
     151                 : 
     152                 :   // nsWrapperCache
     153               0 :   virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
     154                 :                                bool *triedToWrap)
     155                 :   {
     156                 :     return mozilla::dom::binding::HTMLCollection::create(cx, scope, this,
     157               0 :                                                          triedToWrap);
     158                 :   }
     159                 : 
     160                 :   nsHTMLFormElement* mForm;  // WEAK - the form owns me
     161                 : 
     162                 :   nsTArray<nsGenericHTMLFormElement*> mElements;  // Holds WEAK references - bug 36639
     163                 : 
     164                 :   // This array holds on to all form controls that are not contained
     165                 :   // in mElements (form.elements in JS, see ShouldBeInFormControl()).
     166                 :   // This is needed to properly clean up the bi-directional references
     167                 :   // (both weak and strong) between the form and its form controls.
     168                 : 
     169                 :   nsTArray<nsGenericHTMLFormElement*> mNotInElements; // Holds WEAK references
     170                 : 
     171            1464 :   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsFormControlList)
     172                 : 
     173                 : protected:
     174                 :   // Drop all our references to the form elements
     175                 :   void Clear();
     176                 : 
     177                 :   // Flush out the content model so it's up to date.
     178                 :   void FlushPendingNotifications();
     179                 :   
     180                 :   // A map from an ID or NAME attribute to the form control(s), this
     181                 :   // hash holds strong references either to the named form control, or
     182                 :   // to a list of named form controls, in the case where this hash
     183                 :   // holds on to a list of named form controls the list has weak
     184                 :   // references to the form control.
     185                 : 
     186                 :   nsInterfaceHashtable<nsStringHashKey,nsISupports> mNameLookupTable;
     187                 : };
     188                 : 
     189                 : static bool
     190               0 : ShouldBeInElements(nsIFormControl* aFormControl)
     191                 : {
     192                 :   // For backwards compatibility (with 4.x and IE) we must not add
     193                 :   // <input type=image> elements to the list of form controls in a
     194                 :   // form.
     195                 : 
     196               0 :   switch (aFormControl->GetType()) {
     197                 :   case NS_FORM_BUTTON_BUTTON :
     198                 :   case NS_FORM_BUTTON_RESET :
     199                 :   case NS_FORM_BUTTON_SUBMIT :
     200                 :   case NS_FORM_INPUT_BUTTON :
     201                 :   case NS_FORM_INPUT_CHECKBOX :
     202                 :   case NS_FORM_INPUT_EMAIL :
     203                 :   case NS_FORM_INPUT_FILE :
     204                 :   case NS_FORM_INPUT_HIDDEN :
     205                 :   case NS_FORM_INPUT_RESET :
     206                 :   case NS_FORM_INPUT_PASSWORD :
     207                 :   case NS_FORM_INPUT_RADIO :
     208                 :   case NS_FORM_INPUT_SEARCH :
     209                 :   case NS_FORM_INPUT_SUBMIT :
     210                 :   case NS_FORM_INPUT_TEXT :
     211                 :   case NS_FORM_INPUT_TEL :
     212                 :   case NS_FORM_INPUT_URL :
     213                 :   case NS_FORM_SELECT :
     214                 :   case NS_FORM_TEXTAREA :
     215                 :   case NS_FORM_FIELDSET :
     216                 :   case NS_FORM_OBJECT :
     217                 :   case NS_FORM_OUTPUT :
     218               0 :     return true;
     219                 :   }
     220                 : 
     221                 :   // These form control types are not supposed to end up in the
     222                 :   // form.elements array
     223                 :   //
     224                 :   // NS_FORM_INPUT_IMAGE
     225                 :   // NS_FORM_LABEL
     226                 :   // NS_FORM_PROGRESS
     227                 : 
     228               0 :   return false;
     229                 : }
     230                 : 
     231                 : // nsHTMLFormElement implementation
     232                 : 
     233                 : // construction, destruction
     234                 : nsGenericHTMLElement*
     235               0 : NS_NewHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo,
     236                 :                       FromParser aFromParser)
     237                 : {
     238               0 :   nsHTMLFormElement* it = new nsHTMLFormElement(aNodeInfo);
     239                 : 
     240               0 :   nsresult rv = it->Init();
     241                 : 
     242               0 :   if (NS_FAILED(rv)) {
     243               0 :     delete it;
     244               0 :     return nsnull;
     245                 :   }
     246                 : 
     247               0 :   return it;
     248                 : }
     249                 : 
     250               0 : nsHTMLFormElement::nsHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     251                 :   : nsGenericHTMLElement(aNodeInfo),
     252                 :     mGeneratingSubmit(false),
     253                 :     mGeneratingReset(false),
     254                 :     mIsSubmitting(false),
     255                 :     mDeferSubmission(false),
     256                 :     mNotifiedObservers(false),
     257                 :     mNotifiedObserversResult(false),
     258                 :     mSubmitPopupState(openAbused),
     259                 :     mSubmitInitiatedFromUserInput(false),
     260                 :     mPendingSubmission(nsnull),
     261                 :     mSubmittingRequest(nsnull),
     262                 :     mDefaultSubmitElement(nsnull),
     263                 :     mFirstSubmitInElements(nsnull),
     264                 :     mFirstSubmitNotInElements(nsnull),
     265                 :     mInvalidElementsCount(0),
     266               0 :     mEverTriedInvalidSubmit(false)
     267                 : {
     268               0 : }
     269                 : 
     270               0 : nsHTMLFormElement::~nsHTMLFormElement()
     271                 : {
     272               0 :   if (mControls) {
     273               0 :     mControls->DropFormReference();
     274                 :   }
     275               0 : }
     276                 : 
     277                 : nsresult
     278               0 : nsHTMLFormElement::Init()
     279                 : {
     280               0 :   mControls = new nsFormControlList(this);
     281               0 :   if (!mControls) {
     282               0 :     return NS_ERROR_OUT_OF_MEMORY;
     283                 :   }
     284                 : 
     285               0 :   nsresult rv = mControls->Init();
     286                 :   
     287               0 :   if (NS_FAILED(rv))
     288                 :   {
     289               0 :     mControls = nsnull;
     290               0 :     return rv;
     291                 :   }
     292                 :   
     293               0 :   NS_ENSURE_TRUE(mSelectedRadioButtons.Init(4),
     294                 :                  NS_ERROR_OUT_OF_MEMORY);
     295               0 :   NS_ENSURE_TRUE(mRequiredRadioButtonCounts.Init(4),
     296                 :                  NS_ERROR_OUT_OF_MEMORY);
     297               0 :   NS_ENSURE_TRUE(mValueMissingRadioGroups.Init(4),
     298                 :                  NS_ERROR_OUT_OF_MEMORY);
     299                 : 
     300               0 :   return NS_OK;
     301                 : }
     302                 : 
     303                 : 
     304                 : // nsISupports
     305                 : 
     306                 : static PLDHashOperator
     307               0 : ElementTraverser(const nsAString& key, nsIDOMHTMLInputElement* element,
     308                 :                  void* userArg)
     309                 : {
     310                 :   nsCycleCollectionTraversalCallback *cb = 
     311               0 :     static_cast<nsCycleCollectionTraversalCallback*>(userArg);
     312                 :  
     313               0 :   cb->NoteXPCOMChild(element);
     314               0 :   return PL_DHASH_NEXT;
     315                 : }
     316                 : 
     317            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLFormElement)
     318               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLFormElement,
     319                 :                                                   nsGenericHTMLElement)
     320               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mControls,
     321                 :                                                        nsIDOMHTMLCollection)
     322               0 :   tmp->mSelectedRadioButtons.EnumerateRead(ElementTraverser, &cb);
     323               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     324                 : 
     325               0 : NS_IMPL_ADDREF_INHERITED(nsHTMLFormElement, nsGenericElement) 
     326               0 : NS_IMPL_RELEASE_INHERITED(nsHTMLFormElement, nsGenericElement) 
     327                 : 
     328                 : 
     329               0 : DOMCI_NODE_DATA(HTMLFormElement, nsHTMLFormElement)
     330                 : 
     331                 : // QueryInterface implementation for nsHTMLFormElement
     332               0 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLFormElement)
     333               0 :   NS_HTML_CONTENT_INTERFACE_TABLE4(nsHTMLFormElement,
     334                 :                                    nsIDOMHTMLFormElement,
     335                 :                                    nsIForm,
     336                 :                                    nsIWebProgressListener,
     337                 :                                    nsIRadioGroupContainer)
     338               0 :   NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLFormElement,
     339                 :                                                nsGenericHTMLElement)
     340               0 : NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLFormElement)
     341                 : 
     342                 : 
     343                 : // nsIDOMHTMLFormElement
     344                 : 
     345               0 : NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsHTMLFormElement)
     346                 : 
     347                 : NS_IMETHODIMP
     348               0 : nsHTMLFormElement::GetElements(nsIDOMHTMLCollection** aElements)
     349                 : {
     350               0 :   *aElements = mControls;
     351               0 :   NS_ADDREF(*aElements);
     352               0 :   return NS_OK;
     353                 : }
     354                 : 
     355                 : nsresult
     356               0 : nsHTMLFormElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
     357                 :                            nsIAtom* aPrefix, const nsAString& aValue,
     358                 :                            bool aNotify)
     359                 : {
     360               0 :   if ((aName == nsGkAtoms::action || aName == nsGkAtoms::target) &&
     361                 :       aNameSpaceID == kNameSpaceID_None) {
     362               0 :     if (mPendingSubmission) {
     363                 :       // aha, there is a pending submission that means we're in
     364                 :       // the script and we need to flush it. let's tell it
     365                 :       // that the event was ignored to force the flush.
     366                 :       // the second argument is not playing a role at all.
     367               0 :       FlushPendingSubmission();
     368                 :     }
     369                 :     // Don't forget we've notified the password manager already if the
     370                 :     // page sets the action/target in the during submit. (bug 343182)
     371               0 :     bool notifiedObservers = mNotifiedObservers;
     372               0 :     ForgetCurrentSubmission();
     373               0 :     mNotifiedObservers = notifiedObservers;
     374                 :   }
     375                 :   return nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
     376               0 :                                        aNotify);
     377                 : }
     378                 : 
     379                 : nsresult
     380               0 : nsHTMLFormElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
     381                 :                                 const nsAttrValue* aValue, bool aNotify)
     382                 : {
     383               0 :   if (aName == nsGkAtoms::novalidate && aNameSpaceID == kNameSpaceID_None) {
     384                 :     // Update all form elements states because they might be [no longer]
     385                 :     // affected by :-moz-ui-valid or :-moz-ui-invalid.
     386               0 :     for (PRUint32 i = 0, length = mControls->mElements.Length();
     387                 :          i < length; ++i) {
     388               0 :       mControls->mElements[i]->UpdateState(true);
     389                 :     }
     390                 : 
     391               0 :     for (PRUint32 i = 0, length = mControls->mNotInElements.Length();
     392                 :          i < length; ++i) {
     393               0 :       mControls->mNotInElements[i]->UpdateState(true);
     394                 :     }
     395                 :   }
     396                 : 
     397               0 :   return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue, aNotify);
     398                 : }
     399                 : 
     400               0 : NS_IMPL_STRING_ATTR(nsHTMLFormElement, AcceptCharset, acceptcharset)
     401               0 : NS_IMPL_ACTION_ATTR(nsHTMLFormElement, Action, action)
     402               0 : NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLFormElement, Autocomplete, autocomplete,
     403                 :                                 kFormDefaultAutocomplete->tag)
     404               0 : NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLFormElement, Enctype, enctype,
     405                 :                                 kFormDefaultEnctype->tag)
     406               0 : NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLFormElement, Method, method,
     407                 :                                 kFormDefaultMethod->tag)
     408               0 : NS_IMPL_BOOL_ATTR(nsHTMLFormElement, NoValidate, novalidate)
     409               0 : NS_IMPL_STRING_ATTR(nsHTMLFormElement, Name, name)
     410               0 : NS_IMPL_STRING_ATTR(nsHTMLFormElement, Target, target)
     411                 : 
     412                 : NS_IMETHODIMP
     413               0 : nsHTMLFormElement::Submit()
     414                 : {
     415                 :   // Send the submit event
     416               0 :   nsresult rv = NS_OK;
     417               0 :   nsRefPtr<nsPresContext> presContext = GetPresContext();
     418               0 :   if (mPendingSubmission) {
     419                 :     // aha, we have a pending submission that was not flushed
     420                 :     // (this happens when form.submit() is called twice)
     421                 :     // we have to delete it and build a new one since values
     422                 :     // might have changed inbetween (we emulate IE here, that's all)
     423               0 :     mPendingSubmission = nsnull;
     424                 :   }
     425                 : 
     426               0 :   rv = DoSubmitOrReset(nsnull, NS_FORM_SUBMIT);
     427               0 :   return rv;
     428                 : }
     429                 : 
     430                 : NS_IMETHODIMP
     431               0 : nsHTMLFormElement::Reset()
     432                 : {
     433               0 :   nsFormEvent event(true, NS_FORM_RESET);
     434                 :   nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this), nsnull,
     435               0 :                               &event);
     436               0 :   return NS_OK;
     437                 : }
     438                 : 
     439                 : NS_IMETHODIMP
     440               0 : nsHTMLFormElement::CheckValidity(bool* retVal)
     441                 : {
     442               0 :   *retVal = CheckFormValidity(nsnull);
     443               0 :   return NS_OK;
     444                 : }
     445                 : 
     446                 : bool
     447               0 : nsHTMLFormElement::ParseAttribute(PRInt32 aNamespaceID,
     448                 :                                   nsIAtom* aAttribute,
     449                 :                                   const nsAString& aValue,
     450                 :                                   nsAttrValue& aResult)
     451                 : {
     452               0 :   if (aNamespaceID == kNameSpaceID_None) {
     453               0 :     if (aAttribute == nsGkAtoms::method) {
     454               0 :       return aResult.ParseEnumValue(aValue, kFormMethodTable, false);
     455                 :     }
     456               0 :     if (aAttribute == nsGkAtoms::enctype) {
     457               0 :       return aResult.ParseEnumValue(aValue, kFormEnctypeTable, false);
     458                 :     }
     459               0 :     if (aAttribute == nsGkAtoms::autocomplete) {
     460               0 :       return aResult.ParseEnumValue(aValue, kFormAutocompleteTable, false);
     461                 :     }
     462                 :   }
     463                 : 
     464                 :   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
     465               0 :                                               aResult);
     466                 : }
     467                 : 
     468                 : nsresult
     469               0 : nsHTMLFormElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
     470                 :                               nsIContent* aBindingParent,
     471                 :                               bool aCompileEventHandlers)
     472                 : {
     473                 :   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
     474                 :                                                  aBindingParent,
     475               0 :                                                  aCompileEventHandlers);
     476               0 :   NS_ENSURE_SUCCESS(rv, rv);
     477                 : 
     478               0 :   nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(aDocument));
     479               0 :   if (htmlDoc) {
     480               0 :     htmlDoc->AddedForm();
     481                 :   }
     482                 : 
     483               0 :   return rv;
     484                 : }
     485                 : 
     486                 : static void
     487               0 : MarkOrphans(const nsTArray<nsGenericHTMLFormElement*> aArray)
     488                 : {
     489               0 :   PRUint32 length = aArray.Length();
     490               0 :   for (PRUint32 i = 0; i < length; ++i) {
     491               0 :     aArray[i]->SetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
     492                 :   }
     493               0 : }
     494                 : 
     495                 : static void
     496               0 : CollectOrphans(nsINode* aRemovalRoot, nsTArray<nsGenericHTMLFormElement*> aArray
     497                 : #ifdef DEBUG
     498                 :                , nsIDOMHTMLFormElement* aThisForm
     499                 : #endif
     500                 :                )
     501                 : {
     502                 :   // Put a script blocker around all the notifications we're about to do.
     503               0 :   nsAutoScriptBlocker scriptBlocker;
     504                 : 
     505                 :   // Walk backwards so that if we remove elements we can just keep iterating
     506               0 :   PRUint32 length = aArray.Length();
     507               0 :   for (PRUint32 i = length; i > 0; --i) {
     508               0 :     nsGenericHTMLFormElement* node = aArray[i-1];
     509                 : 
     510                 :     // Now if MAYBE_ORPHAN_FORM_ELEMENT is not set, that would mean that the
     511                 :     // node is in fact a descendant of the form and hence should stay in the
     512                 :     // form.  If it _is_ set, then we need to check whether the node is a
     513                 :     // descendant of aRemovalRoot.  If it is, we leave it in the form.  See
     514                 :     // also the code in nsGenericHTMLFormElement::FindForm.
     515                 : #ifdef DEBUG
     516               0 :     bool removed = false;
     517                 : #endif
     518               0 :     if (node->HasFlag(MAYBE_ORPHAN_FORM_ELEMENT)) {
     519               0 :       node->UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
     520               0 :       if (!nsContentUtils::ContentIsDescendantOf(node, aRemovalRoot)) {
     521               0 :         node->ClearForm(true);
     522                 : 
     523                 :         // When a form control loses its form owner, its state can change.
     524               0 :         node->UpdateState(true);
     525                 : #ifdef DEBUG
     526               0 :         removed = true;
     527                 : #endif
     528                 :       }
     529                 :     }
     530                 : 
     531                 : #ifdef DEBUG
     532               0 :     if (!removed) {
     533               0 :       nsCOMPtr<nsIDOMHTMLFormElement> form;
     534               0 :       node->GetForm(getter_AddRefs(form));
     535               0 :       NS_ASSERTION(form == aThisForm, "How did that happen?");
     536                 :     }
     537                 : #endif /* DEBUG */
     538                 :   }
     539               0 : }
     540                 : 
     541                 : void
     542               0 : nsHTMLFormElement::UnbindFromTree(bool aDeep, bool aNullParent)
     543                 : {
     544               0 :   nsCOMPtr<nsIHTMLDocument> oldDocument = do_QueryInterface(GetCurrentDoc());
     545                 : 
     546                 :   // Mark all of our controls as maybe being orphans
     547               0 :   MarkOrphans(mControls->mElements);
     548               0 :   MarkOrphans(mControls->mNotInElements);
     549                 : 
     550               0 :   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
     551                 : 
     552               0 :   nsINode* ancestor = this;
     553                 :   nsINode* cur;
     554               0 :   do {
     555               0 :     cur = ancestor->GetNodeParent();
     556               0 :     if (!cur) {
     557                 :       break;
     558                 :     }
     559               0 :     ancestor = cur;
     560                 :   } while (1);
     561                 :   
     562               0 :   CollectOrphans(ancestor, mControls->mElements
     563                 : #ifdef DEBUG
     564                 :                  , this
     565                 : #endif                 
     566               0 :                  );
     567               0 :   CollectOrphans(ancestor, mControls->mNotInElements
     568                 : #ifdef DEBUG
     569                 :                  , this
     570                 : #endif                 
     571               0 :                  );
     572                 : 
     573               0 :   if (oldDocument) {
     574               0 :     oldDocument->RemovedForm();
     575                 :   }     
     576               0 :   ForgetCurrentSubmission();
     577               0 : }
     578                 : 
     579                 : nsresult
     580               0 : nsHTMLFormElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
     581                 : {
     582               0 :   aVisitor.mWantsWillHandleEvent = true;
     583               0 :   if (aVisitor.mEvent->originalTarget == static_cast<nsIContent*>(this)) {
     584               0 :     PRUint32 msg = aVisitor.mEvent->message;
     585               0 :     if (msg == NS_FORM_SUBMIT) {
     586               0 :       if (mGeneratingSubmit) {
     587               0 :         aVisitor.mCanHandle = false;
     588               0 :         return NS_OK;
     589                 :       }
     590               0 :       mGeneratingSubmit = true;
     591                 : 
     592                 :       // let the form know that it needs to defer the submission,
     593                 :       // that means that if there are scripted submissions, the
     594                 :       // latest one will be deferred until after the exit point of the handler.
     595               0 :       mDeferSubmission = true;
     596                 :     }
     597               0 :     else if (msg == NS_FORM_RESET) {
     598               0 :       if (mGeneratingReset) {
     599               0 :         aVisitor.mCanHandle = false;
     600               0 :         return NS_OK;
     601                 :       }
     602               0 :       mGeneratingReset = true;
     603                 :     }
     604                 :   }
     605               0 :   return nsGenericHTMLElement::PreHandleEvent(aVisitor);
     606                 : }
     607                 : 
     608                 : nsresult
     609               0 : nsHTMLFormElement::WillHandleEvent(nsEventChainPostVisitor& aVisitor)
     610                 : {
     611                 :   // If this is the bubble stage and there is a nested form below us which
     612                 :   // received a submit event we do *not* want to handle the submit event
     613                 :   // for this form too.
     614               0 :   if ((aVisitor.mEvent->message == NS_FORM_SUBMIT ||
     615                 :        aVisitor.mEvent->message == NS_FORM_RESET) &&
     616                 :       aVisitor.mEvent->flags & NS_EVENT_FLAG_BUBBLE &&
     617               0 :       aVisitor.mEvent->originalTarget != static_cast<nsIContent*>(this)) {
     618               0 :     aVisitor.mEvent->flags |= NS_EVENT_FLAG_STOP_DISPATCH;
     619                 :   }
     620               0 :   return NS_OK;
     621                 : }
     622                 : 
     623                 : nsresult
     624               0 : nsHTMLFormElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
     625                 : {
     626               0 :   if (aVisitor.mEvent->originalTarget == static_cast<nsIContent*>(this)) {
     627               0 :     PRUint32 msg = aVisitor.mEvent->message;
     628               0 :     if (msg == NS_FORM_SUBMIT) {
     629                 :       // let the form know not to defer subsequent submissions
     630               0 :       mDeferSubmission = false;
     631                 :     }
     632                 : 
     633               0 :     if (aVisitor.mEventStatus == nsEventStatus_eIgnore) {
     634               0 :       switch (msg) {
     635                 :         case NS_FORM_RESET:
     636                 :         case NS_FORM_SUBMIT:
     637                 :         {
     638               0 :           if (mPendingSubmission && msg == NS_FORM_SUBMIT) {
     639                 :             // tell the form to forget a possible pending submission.
     640                 :             // the reason is that the script returned true (the event was
     641                 :             // ignored) so if there is a stored submission, it will miss
     642                 :             // the name/value of the submitting element, thus we need
     643                 :             // to forget it and the form element will build a new one
     644               0 :             mPendingSubmission = nsnull;
     645                 :           }
     646               0 :           DoSubmitOrReset(aVisitor.mEvent, msg);
     647                 :         }
     648               0 :         break;
     649                 :       }
     650                 :     } else {
     651               0 :       if (msg == NS_FORM_SUBMIT) {
     652                 :         // tell the form to flush a possible pending submission.
     653                 :         // the reason is that the script returned false (the event was
     654                 :         // not ignored) so if there is a stored submission, it needs to
     655                 :         // be submitted immediatelly.
     656               0 :         FlushPendingSubmission();
     657                 :       }
     658                 :     }
     659                 : 
     660               0 :     if (msg == NS_FORM_SUBMIT) {
     661               0 :       mGeneratingSubmit = false;
     662                 :     }
     663               0 :     else if (msg == NS_FORM_RESET) {
     664               0 :       mGeneratingReset = false;
     665                 :     }
     666                 :   }
     667               0 :   return NS_OK;
     668                 : }
     669                 : 
     670                 : nsresult
     671               0 : nsHTMLFormElement::DoSubmitOrReset(nsEvent* aEvent,
     672                 :                                    PRInt32 aMessage)
     673                 : {
     674                 :   // Make sure the presentation is up-to-date
     675               0 :   nsIDocument* doc = GetCurrentDoc();
     676               0 :   if (doc) {
     677               0 :     doc->FlushPendingNotifications(Flush_ContentAndNotify);
     678                 :   }
     679                 : 
     680                 :   // JBK Don't get form frames anymore - bug 34297
     681                 : 
     682                 :   // Submit or Reset the form
     683               0 :   if (NS_FORM_RESET == aMessage) {
     684               0 :     return DoReset();
     685                 :   }
     686                 : 
     687               0 :   if (NS_FORM_SUBMIT == aMessage) {
     688                 :     // Don't submit if we're not in a document.
     689               0 :     if (!doc) {
     690               0 :       return NS_OK;
     691                 :     }
     692               0 :     return DoSubmit(aEvent);
     693                 :   }
     694                 : 
     695               0 :   MOZ_ASSERT(false);
     696               0 :   return NS_OK;
     697                 : }
     698                 : 
     699                 : nsresult
     700               0 : nsHTMLFormElement::DoReset()
     701                 : {
     702                 :   // JBK walk the elements[] array instead of form frame controls - bug 34297
     703               0 :   PRUint32 numElements = GetElementCount();
     704               0 :   for (PRUint32 elementX = 0; elementX < numElements; ++elementX) {
     705                 :     // Hold strong ref in case the reset does something weird
     706               0 :     nsCOMPtr<nsIFormControl> controlNode = GetElementAt(elementX);
     707               0 :     if (controlNode) {
     708               0 :       controlNode->Reset();
     709                 :     }
     710                 :   }
     711                 : 
     712               0 :   return NS_OK;
     713                 : }
     714                 : 
     715                 : #define NS_ENSURE_SUBMIT_SUCCESS(rv)                                          \
     716                 :   if (NS_FAILED(rv)) {                                                        \
     717                 :     ForgetCurrentSubmission();                                                \
     718                 :     return rv;                                                                \
     719                 :   }
     720                 : 
     721                 : nsresult
     722               0 : nsHTMLFormElement::DoSubmit(nsEvent* aEvent)
     723                 : {
     724               0 :   NS_ASSERTION(GetCurrentDoc(), "Should never get here without a current doc");
     725                 : 
     726               0 :   if (mIsSubmitting) {
     727               0 :     NS_WARNING("Preventing double form submission");
     728                 :     // XXX Should this return an error?
     729               0 :     return NS_OK;
     730                 :   }
     731                 : 
     732                 :   // Mark us as submitting so that we don't try to submit again
     733               0 :   mIsSubmitting = true;
     734               0 :   NS_ASSERTION(!mWebProgress && !mSubmittingRequest, "Web progress / submitting request should not exist here!");
     735                 : 
     736               0 :   nsAutoPtr<nsFormSubmission> submission;
     737                 : 
     738                 :   //
     739                 :   // prepare the submission object
     740                 :   //
     741               0 :   nsresult rv = BuildSubmission(getter_Transfers(submission), aEvent);
     742               0 :   if (NS_FAILED(rv)) {
     743               0 :     mIsSubmitting = false;
     744               0 :     return rv;
     745                 :   }
     746                 : 
     747                 :   // XXXbz if the script global is that for an sXBL/XBL2 doc, it won't
     748                 :   // be a window...
     749               0 :   nsPIDOMWindow *window = OwnerDoc()->GetWindow();
     750                 : 
     751               0 :   if (window) {
     752               0 :     mSubmitPopupState = window->GetPopupControlState();
     753                 :   } else {
     754               0 :     mSubmitPopupState = openAbused;
     755                 :   }
     756                 : 
     757               0 :   mSubmitInitiatedFromUserInput = nsEventStateManager::IsHandlingUserInput();
     758                 : 
     759               0 :   if(mDeferSubmission) { 
     760                 :     // we are in an event handler, JS submitted so we have to
     761                 :     // defer this submission. let's remember it and return
     762                 :     // without submitting
     763               0 :     mPendingSubmission = submission;
     764                 :     // ensure reentrancy
     765               0 :     mIsSubmitting = false;
     766               0 :     return NS_OK; 
     767                 :   } 
     768                 :   
     769                 :   // 
     770                 :   // perform the submission
     771                 :   //
     772               0 :   return SubmitSubmission(submission); 
     773                 : }
     774                 : 
     775                 : nsresult
     776               0 : nsHTMLFormElement::BuildSubmission(nsFormSubmission** aFormSubmission, 
     777                 :                                    nsEvent* aEvent)
     778                 : {
     779               0 :   NS_ASSERTION(!mPendingSubmission, "tried to build two submissions!");
     780                 : 
     781                 :   // Get the originating frame (failure is non-fatal)
     782               0 :   nsGenericHTMLElement* originatingElement = nsnull;
     783               0 :   if (aEvent) {
     784               0 :     if (NS_FORM_EVENT == aEvent->eventStructType) {
     785               0 :       nsIContent* originator = ((nsFormEvent *)aEvent)->originator;
     786               0 :       if (originator) {
     787               0 :         if (!originator->IsHTML()) {
     788               0 :           return NS_ERROR_UNEXPECTED;
     789                 :         }
     790                 :         originatingElement =
     791               0 :           static_cast<nsGenericHTMLElement*>(((nsFormEvent *)aEvent)->originator);
     792                 :       }
     793                 :     }
     794                 :   }
     795                 : 
     796                 :   nsresult rv;
     797                 : 
     798                 :   //
     799                 :   // Get the submission object
     800                 :   //
     801               0 :   rv = GetSubmissionFromForm(this, originatingElement, aFormSubmission);
     802               0 :   NS_ENSURE_SUBMIT_SUCCESS(rv);
     803                 : 
     804                 :   //
     805                 :   // Dump the data into the submission object
     806                 :   //
     807               0 :   rv = WalkFormElements(*aFormSubmission);
     808               0 :   NS_ENSURE_SUBMIT_SUCCESS(rv);
     809                 : 
     810               0 :   return NS_OK;
     811                 : }
     812                 : 
     813                 : nsresult
     814               0 : nsHTMLFormElement::SubmitSubmission(nsFormSubmission* aFormSubmission)
     815                 : {
     816                 :   nsresult rv;
     817               0 :   nsIContent* originatingElement = aFormSubmission->GetOriginatingElement();
     818                 : 
     819                 :   //
     820                 :   // Get the action and target
     821                 :   //
     822               0 :   nsCOMPtr<nsIURI> actionURI;
     823               0 :   rv = GetActionURL(getter_AddRefs(actionURI), originatingElement);
     824               0 :   NS_ENSURE_SUBMIT_SUCCESS(rv);
     825                 : 
     826               0 :   if (!actionURI) {
     827               0 :     mIsSubmitting = false;
     828               0 :     return NS_OK;
     829                 :   }
     830                 : 
     831                 :   // If there is no link handler, then we won't actually be able to submit.
     832               0 :   nsIDocument* doc = GetCurrentDoc();
     833               0 :   nsCOMPtr<nsISupports> container = doc ? doc->GetContainer() : nsnull;
     834               0 :   nsCOMPtr<nsILinkHandler> linkHandler(do_QueryInterface(container));
     835               0 :   if (!linkHandler || IsEditable()) {
     836               0 :     mIsSubmitting = false;
     837               0 :     return NS_OK;
     838                 :   }
     839                 : 
     840                 :   // javascript URIs are not really submissions; they just call a function.
     841                 :   // Also, they may synchronously call submit(), and we want them to be able to
     842                 :   // do so while still disallowing other double submissions. (Bug 139798)
     843                 :   // Note that any other URI types that are of equivalent type should also be
     844                 :   // added here.
     845                 :   // XXXbz this is a mess.  The real issue here is that nsJSChannel sets the
     846                 :   // LOAD_BACKGROUND flag, so doesn't notify us, compounded by the fact that
     847                 :   // the JS executes before we forget the submission in OnStateChange on
     848                 :   // STATE_STOP.  As a result, we have to make sure that we simply pretend
     849                 :   // we're not submitting when submitting to a JS URL.  That's kinda bogus, but
     850                 :   // there we are.
     851               0 :   bool schemeIsJavaScript = false;
     852               0 :   if (NS_SUCCEEDED(actionURI->SchemeIs("javascript", &schemeIsJavaScript)) &&
     853                 :       schemeIsJavaScript) {
     854               0 :     mIsSubmitting = false;
     855                 :   }
     856                 : 
     857                 :   // The target is the originating element formtarget attribute if the element
     858                 :   // is a submit control and has such an attribute.
     859                 :   // Otherwise, the target is the form owner's target attribute,
     860                 :   // if it has such an attribute.
     861                 :   // Finally, if one of the child nodes of the head element is a base element
     862                 :   // with a target attribute, then the value of the target attribute of the
     863                 :   // first such base element; or, if there is no such element, the empty string.
     864               0 :   nsAutoString target;
     865               0 :   if (!(originatingElement && originatingElement->GetAttr(kNameSpaceID_None,
     866                 :                                                           nsGkAtoms::formtarget,
     867               0 :                                                           target)) &&
     868               0 :       !GetAttr(kNameSpaceID_None, nsGkAtoms::target, target)) {
     869               0 :     GetBaseTarget(target);
     870                 :   }
     871                 : 
     872                 :   //
     873                 :   // Notify observers of submit
     874                 :   //
     875               0 :   bool cancelSubmit = false;
     876               0 :   if (mNotifiedObservers) {
     877               0 :     cancelSubmit = mNotifiedObserversResult;
     878                 :   } else {
     879               0 :     rv = NotifySubmitObservers(actionURI, &cancelSubmit, true);
     880               0 :     NS_ENSURE_SUBMIT_SUCCESS(rv);
     881                 :   }
     882                 : 
     883               0 :   if (cancelSubmit) {
     884               0 :     mIsSubmitting = false;
     885               0 :     return NS_OK;
     886                 :   }
     887                 : 
     888               0 :   cancelSubmit = false;
     889               0 :   rv = NotifySubmitObservers(actionURI, &cancelSubmit, false);
     890               0 :   NS_ENSURE_SUBMIT_SUCCESS(rv);
     891                 : 
     892               0 :   if (cancelSubmit) {
     893               0 :     mIsSubmitting = false;
     894               0 :     return NS_OK;
     895                 :   }
     896                 : 
     897                 :   //
     898                 :   // Submit
     899                 :   //
     900               0 :   nsCOMPtr<nsIDocShell> docShell;
     901                 : 
     902                 :   {
     903               0 :     nsAutoPopupStatePusher popupStatePusher(mSubmitPopupState);
     904                 : 
     905                 :     nsAutoHandlingUserInputStatePusher userInpStatePusher(
     906                 :                                          mSubmitInitiatedFromUserInput,
     907               0 :                                          nsnull, doc);
     908                 : 
     909               0 :     nsCOMPtr<nsIInputStream> postDataStream;
     910                 :     rv = aFormSubmission->GetEncodedSubmission(actionURI,
     911               0 :                                                getter_AddRefs(postDataStream));
     912               0 :     NS_ENSURE_SUBMIT_SUCCESS(rv);
     913                 : 
     914               0 :     rv = linkHandler->OnLinkClickSync(this, actionURI,
     915                 :                                       target.get(),
     916                 :                                       postDataStream, nsnull,
     917               0 :                                       getter_AddRefs(docShell),
     918               0 :                                       getter_AddRefs(mSubmittingRequest));
     919               0 :     NS_ENSURE_SUBMIT_SUCCESS(rv);
     920                 :   }
     921                 : 
     922                 :   // Even if the submit succeeds, it's possible for there to be no docshell
     923                 :   // or request; for example, if it's to a named anchor within the same page
     924                 :   // the submit will not really do anything.
     925               0 :   if (docShell) {
     926                 :     // If the channel is pending, we have to listen for web progress.
     927               0 :     bool pending = false;
     928               0 :     mSubmittingRequest->IsPending(&pending);
     929               0 :     if (pending && !schemeIsJavaScript) {
     930               0 :       nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
     931               0 :       NS_ASSERTION(webProgress, "nsIDocShell not converted to nsIWebProgress!");
     932               0 :       rv = webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_ALL);
     933               0 :       NS_ENSURE_SUBMIT_SUCCESS(rv);
     934               0 :       mWebProgress = do_GetWeakReference(webProgress);
     935               0 :       NS_ASSERTION(mWebProgress, "can't hold weak ref to webprogress!");
     936                 :     } else {
     937               0 :       ForgetCurrentSubmission();
     938                 :     }
     939                 :   } else {
     940               0 :     ForgetCurrentSubmission();
     941                 :   }
     942                 : 
     943               0 :   return rv;
     944                 : }
     945                 : 
     946                 : nsresult
     947               0 : nsHTMLFormElement::NotifySubmitObservers(nsIURI* aActionURL,
     948                 :                                          bool* aCancelSubmit,
     949                 :                                          bool    aEarlyNotify)
     950                 : {
     951                 :   // If this is the first form, bring alive the first form submit
     952                 :   // category observers
     953               0 :   if (!gFirstFormSubmitted) {
     954               0 :     gFirstFormSubmitted = true;
     955                 :     NS_CreateServicesFromCategory(NS_FIRST_FORMSUBMIT_CATEGORY,
     956                 :                                   nsnull,
     957               0 :                                   NS_FIRST_FORMSUBMIT_CATEGORY);
     958                 :   }
     959                 : 
     960                 :   // Notify observers that the form is being submitted.
     961                 :   nsCOMPtr<nsIObserverService> service =
     962               0 :     mozilla::services::GetObserverService();
     963               0 :   if (!service)
     964               0 :     return NS_ERROR_FAILURE;
     965                 : 
     966               0 :   nsCOMPtr<nsISimpleEnumerator> theEnum;
     967               0 :   nsresult rv = service->EnumerateObservers(aEarlyNotify ?
     968                 :                                             NS_EARLYFORMSUBMIT_SUBJECT :
     969                 :                                             NS_FORMSUBMIT_SUBJECT,
     970               0 :                                             getter_AddRefs(theEnum));
     971               0 :   NS_ENSURE_SUCCESS(rv, rv);
     972                 : 
     973               0 :   if (theEnum) {
     974               0 :     nsCOMPtr<nsISupports> inst;
     975               0 :     *aCancelSubmit = false;
     976                 : 
     977                 :     // XXXbz what do the submit observers actually want?  The window
     978                 :     // of the document this is shown in?  Or something else?
     979                 :     // sXBL/XBL2 issue
     980               0 :     nsCOMPtr<nsPIDOMWindow> window = OwnerDoc()->GetWindow();
     981                 : 
     982               0 :     bool loop = true;
     983               0 :     while (NS_SUCCEEDED(theEnum->HasMoreElements(&loop)) && loop) {
     984               0 :       theEnum->GetNext(getter_AddRefs(inst));
     985                 : 
     986                 :       nsCOMPtr<nsIFormSubmitObserver> formSubmitObserver(
     987               0 :                       do_QueryInterface(inst));
     988               0 :       if (formSubmitObserver) {
     989               0 :         rv = formSubmitObserver->Notify(this,
     990                 :                                         window,
     991                 :                                         aActionURL,
     992               0 :                                         aCancelSubmit);
     993               0 :         NS_ENSURE_SUCCESS(rv, rv);
     994                 :       }
     995               0 :       if (*aCancelSubmit) {
     996               0 :         return NS_OK;
     997                 :       }
     998                 :     }
     999                 :   }
    1000                 : 
    1001               0 :   return rv;
    1002                 : }
    1003                 : 
    1004                 : 
    1005                 : nsresult
    1006               0 : nsHTMLFormElement::WalkFormElements(nsFormSubmission* aFormSubmission)
    1007                 : {
    1008               0 :   nsTArray<nsGenericHTMLFormElement*> sortedControls;
    1009               0 :   nsresult rv = mControls->GetSortedControls(sortedControls);
    1010               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1011                 : 
    1012                 :   //
    1013                 :   // Walk the list of nodes and call SubmitNamesValues() on the controls
    1014                 :   //
    1015               0 :   PRUint32 len = sortedControls.Length();
    1016               0 :   for (PRUint32 i = 0; i < len; ++i) {
    1017                 :     // Tell the control to submit its name/value pairs to the submission
    1018               0 :     sortedControls[i]->SubmitNamesValues(aFormSubmission);
    1019                 :   }
    1020                 : 
    1021               0 :   return NS_OK;
    1022                 : }
    1023                 : 
    1024                 : // nsIForm
    1025                 : 
    1026                 : NS_IMETHODIMP_(PRUint32)
    1027               0 : nsHTMLFormElement::GetElementCount() const 
    1028                 : {
    1029               0 :   PRUint32 count = nsnull;
    1030               0 :   mControls->GetLength(&count); 
    1031               0 :   return count;
    1032                 : }
    1033                 : 
    1034                 : NS_IMETHODIMP_(nsIFormControl*)
    1035               0 : nsHTMLFormElement::GetElementAt(PRInt32 aIndex) const
    1036                 : {
    1037               0 :   return mControls->mElements.SafeElementAt(aIndex, nsnull);
    1038                 : }
    1039                 : 
    1040                 : /**
    1041                 :  * Compares the position of aControl1 and aControl2 in the document
    1042                 :  * @param aControl1 First control to compare.
    1043                 :  * @param aControl2 Second control to compare.
    1044                 :  * @param aForm Parent form of the controls.
    1045                 :  * @return < 0 if aControl1 is before aControl2,
    1046                 :  *         > 0 if aControl1 is after aControl2,
    1047                 :  *         0 otherwise
    1048                 :  */
    1049                 : static inline PRInt32
    1050               0 : CompareFormControlPosition(nsGenericHTMLFormElement *aControl1,
    1051                 :                            nsGenericHTMLFormElement *aControl2,
    1052                 :                            const nsIContent* aForm)
    1053                 : {
    1054               0 :   NS_ASSERTION(aControl1 != aControl2, "Comparing a form control to itself");
    1055                 : 
    1056               0 :   NS_ASSERTION(aControl1->GetParent() && aControl2->GetParent(),
    1057                 :                "Form controls should always have parents");
    1058                 : 
    1059                 :   // If we pass aForm, we are assuming both controls are form descendants which
    1060                 :   // is not always the case. This function should work but maybe slower.
    1061                 :   // However, checking if both elements are form descendants may be slow too...
    1062                 :   // TODO: remove the prevent asserts fix, see bug 598468.
    1063                 : #ifdef DEBUG
    1064               0 :   nsLayoutUtils::gPreventAssertInCompareTreePosition = true;
    1065               0 :   PRInt32 rVal = nsLayoutUtils::CompareTreePosition(aControl1, aControl2, aForm);
    1066               0 :   nsLayoutUtils::gPreventAssertInCompareTreePosition = false;
    1067                 : 
    1068               0 :   return rVal;
    1069                 : #else // DEBUG
    1070                 :   return nsLayoutUtils::CompareTreePosition(aControl1, aControl2, aForm);
    1071                 : #endif // DEBUG
    1072                 : }
    1073                 :  
    1074                 : #ifdef DEBUG
    1075                 : /**
    1076                 :  * Checks that all form elements are in document order. Asserts if any pair of
    1077                 :  * consecutive elements are not in increasing document order.
    1078                 :  *
    1079                 :  * @param aControls List of form controls to check.
    1080                 :  * @param aForm Parent form of the controls.
    1081                 :  */
    1082                 : static void
    1083               0 : AssertDocumentOrder(const nsTArray<nsGenericHTMLFormElement*>& aControls,
    1084                 :                     nsIContent* aForm)
    1085                 : {
    1086                 :   // TODO: remove the return statement with bug 598468.
    1087                 :   // This is done to prevent asserts in some edge cases.
    1088                 :   return;
    1089                 : 
    1090                 :   // Only iterate if aControls is not empty, since otherwise
    1091                 :   // |aControls.Length() - 1| will be a very large unsigned number... not what
    1092                 :   // we want here.
    1093                 :   if (!aControls.IsEmpty()) {
    1094                 :     for (PRUint32 i = 0; i < aControls.Length() - 1; ++i) {
    1095                 :       NS_ASSERTION(CompareFormControlPosition(aControls[i], aControls[i + 1],
    1096                 :                                               aForm) < 0,
    1097                 :                    "Form controls not ordered correctly");
    1098                 :     }
    1099                 :   }
    1100                 : }
    1101                 : #endif
    1102                 : 
    1103                 : nsresult
    1104               0 : nsHTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
    1105                 :                               bool aUpdateValidity, bool aNotify)
    1106                 : {
    1107               0 :   NS_ASSERTION(aChild->GetParent(), "Form control should have a parent");
    1108                 : 
    1109                 :   // Determine whether to add the new element to the elements or
    1110                 :   // the not-in-elements list.
    1111               0 :   bool childInElements = ShouldBeInElements(aChild);
    1112                 :   nsTArray<nsGenericHTMLFormElement*>& controlList = childInElements ?
    1113               0 :       mControls->mElements : mControls->mNotInElements;
    1114                 :   
    1115               0 :   NS_ASSERTION(controlList.IndexOf(aChild) == controlList.NoIndex,
    1116                 :                "Form control already in form");
    1117                 : 
    1118               0 :   PRUint32 count = controlList.Length();
    1119                 :   nsGenericHTMLFormElement* element;
    1120                 :   
    1121                 :   // Optimize most common case where we insert at the end.
    1122               0 :   bool lastElement = false;
    1123               0 :   PRInt32 position = -1;
    1124               0 :   if (count > 0) {
    1125               0 :     element = controlList[count - 1];
    1126               0 :     position = CompareFormControlPosition(aChild, element, this);
    1127                 :   }
    1128                 : 
    1129                 :   // If this item comes after the last element, or the elements array is
    1130                 :   // empty, we append to the end. Otherwise, we do a binary search to
    1131                 :   // determine where the element should go.
    1132               0 :   if (position >= 0 || count == 0) {
    1133                 :     // WEAK - don't addref
    1134               0 :     controlList.AppendElement(aChild);
    1135               0 :     lastElement = true;
    1136                 :   }
    1137                 :   else {
    1138               0 :     PRInt32 low = 0, mid, high;
    1139               0 :     high = count - 1;
    1140                 :       
    1141               0 :     while (low <= high) {
    1142               0 :       mid = (low + high) / 2;
    1143                 :         
    1144               0 :       element = controlList[mid];
    1145               0 :       position = CompareFormControlPosition(aChild, element, this);
    1146               0 :       if (position >= 0)
    1147               0 :         low = mid + 1;
    1148                 :       else
    1149               0 :         high = mid - 1;
    1150                 :     }
    1151                 :       
    1152                 :     // WEAK - don't addref
    1153               0 :     controlList.InsertElementAt(low, aChild);
    1154                 :   }
    1155                 : 
    1156                 : #ifdef DEBUG
    1157               0 :   AssertDocumentOrder(controlList, this);
    1158                 : #endif
    1159                 : 
    1160               0 :   PRInt32 type = aChild->GetType();
    1161                 : 
    1162                 :   //
    1163                 :   // If it is a password control, and the password manager has not yet been
    1164                 :   // initialized, initialize the password manager
    1165                 :   //
    1166               0 :   if (!gPasswordManagerInitialized && type == NS_FORM_INPUT_PASSWORD) {
    1167                 :     // Initialize the password manager category
    1168               0 :     gPasswordManagerInitialized = true;
    1169                 :     NS_CreateServicesFromCategory(NS_PASSWORDMANAGER_CATEGORY,
    1170                 :                                   nsnull,
    1171               0 :                                   NS_PASSWORDMANAGER_CATEGORY);
    1172                 :   }
    1173                 :  
    1174                 :   // Default submit element handling
    1175               0 :   if (aChild->IsSubmitControl()) {
    1176                 :     // Update mDefaultSubmitElement, mFirstSubmitInElements,
    1177                 :     // mFirstSubmitNotInElements.
    1178                 : 
    1179                 :     nsGenericHTMLFormElement** firstSubmitSlot =
    1180               0 :       childInElements ? &mFirstSubmitInElements : &mFirstSubmitNotInElements;
    1181                 :     
    1182                 :     // The new child is the new first submit in its list if the firstSubmitSlot
    1183                 :     // is currently empty or if the child is before what's currently in the
    1184                 :     // slot.  Note that if we already have a control in firstSubmitSlot and
    1185                 :     // we're appending this element can't possibly replace what's currently in
    1186                 :     // the slot.  Also note that aChild can't become the mDefaultSubmitElement
    1187                 :     // unless it replaces what's in the slot.  If it _does_ replace what's in
    1188                 :     // the slot, it becomes the default submit if either the default submit is
    1189                 :     // what's in the slot or the child is earlier than the default submit.
    1190               0 :     nsGenericHTMLFormElement* oldDefaultSubmit = mDefaultSubmitElement;
    1191               0 :     if (!*firstSubmitSlot ||
    1192               0 :         (!lastElement &&
    1193               0 :          CompareFormControlPosition(aChild, *firstSubmitSlot, this) < 0)) {
    1194                 :       // Update mDefaultSubmitElement if it's currently in a valid state.
    1195                 :       // Valid state means either non-null or null because there are in fact
    1196                 :       // no submit elements around.
    1197               0 :       if ((mDefaultSubmitElement ||
    1198               0 :            (!mFirstSubmitInElements && !mFirstSubmitNotInElements)) &&
    1199                 :           (*firstSubmitSlot == mDefaultSubmitElement ||
    1200                 :            CompareFormControlPosition(aChild,
    1201               0 :                                       mDefaultSubmitElement, this) < 0)) {
    1202               0 :         mDefaultSubmitElement = aChild;
    1203                 :       }
    1204               0 :       *firstSubmitSlot = aChild;
    1205                 :     }
    1206               0 :     NS_POSTCONDITION(mDefaultSubmitElement == mFirstSubmitInElements ||
    1207                 :                      mDefaultSubmitElement == mFirstSubmitNotInElements ||
    1208                 :                      !mDefaultSubmitElement,
    1209                 :                      "What happened here?");
    1210                 : 
    1211                 :     // Notify that the state of the previous default submit element has changed
    1212                 :     // if the element which is the default submit element has changed.  The new
    1213                 :     // default submit element is responsible for its own state update.
    1214               0 :     if (oldDefaultSubmit && oldDefaultSubmit != mDefaultSubmitElement) {
    1215               0 :       oldDefaultSubmit->UpdateState(aNotify);
    1216                 :     }
    1217                 :   }
    1218                 : 
    1219                 :   // If the element is subject to constraint validaton and is invalid, we need
    1220                 :   // to update our internal counter.
    1221               0 :   if (aUpdateValidity) {
    1222               0 :     nsCOMPtr<nsIConstraintValidation> cvElmt = do_QueryObject(aChild);
    1223               0 :     if (cvElmt &&
    1224               0 :         cvElmt->IsCandidateForConstraintValidation() && !cvElmt->IsValid()) {
    1225               0 :       UpdateValidity(false);
    1226                 :     }
    1227                 :   }
    1228                 : 
    1229                 :   // Notify the radio button it's been added to a group
    1230                 :   // This has to be done _after_ UpdateValidity() call to prevent the element
    1231                 :   // being count twice.
    1232               0 :   if (type == NS_FORM_INPUT_RADIO) {
    1233                 :     nsRefPtr<nsHTMLInputElement> radio =
    1234               0 :       static_cast<nsHTMLInputElement*>(aChild);
    1235               0 :     radio->AddedToRadioGroup();
    1236                 :   }
    1237                 : 
    1238               0 :   return NS_OK;
    1239                 : }
    1240                 : 
    1241                 : nsresult
    1242               0 : nsHTMLFormElement::AddElementToTable(nsGenericHTMLFormElement* aChild,
    1243                 :                                      const nsAString& aName)
    1244                 : {
    1245               0 :   return mControls->AddElementToTable(aChild, aName);  
    1246                 : }
    1247                 : 
    1248                 : 
    1249                 : nsresult
    1250               0 : nsHTMLFormElement::RemoveElement(nsGenericHTMLFormElement* aChild,
    1251                 :                                  bool aUpdateValidity)
    1252                 : {
    1253                 :   //
    1254                 :   // Remove it from the radio group if it's a radio button
    1255                 :   //
    1256               0 :   nsresult rv = NS_OK;
    1257               0 :   if (aChild->GetType() == NS_FORM_INPUT_RADIO) {
    1258                 :     nsRefPtr<nsHTMLInputElement> radio =
    1259               0 :       static_cast<nsHTMLInputElement*>(aChild);
    1260               0 :     radio->WillRemoveFromRadioGroup();
    1261                 :   }
    1262                 : 
    1263                 :   // Determine whether to remove the child from the elements list
    1264                 :   // or the not in elements list.
    1265               0 :   bool childInElements = ShouldBeInElements(aChild);
    1266                 :   nsTArray<nsGenericHTMLFormElement*>& controls = childInElements ?
    1267               0 :       mControls->mElements :  mControls->mNotInElements;
    1268                 :   
    1269                 :   // Find the index of the child. This will be used later if necessary
    1270                 :   // to find the default submit.
    1271               0 :   PRUint32 index = controls.IndexOf(aChild);
    1272               0 :   NS_ENSURE_STATE(index != controls.NoIndex);
    1273                 : 
    1274               0 :   controls.RemoveElementAt(index);
    1275                 : 
    1276                 :   // Update our mFirstSubmit* values.
    1277                 :   nsGenericHTMLFormElement** firstSubmitSlot =
    1278               0 :     childInElements ? &mFirstSubmitInElements : &mFirstSubmitNotInElements;
    1279               0 :   if (aChild == *firstSubmitSlot) {
    1280               0 :     *firstSubmitSlot = nsnull;
    1281                 : 
    1282                 :     // We are removing the first submit in this list, find the new first submit
    1283               0 :     PRUint32 length = controls.Length();
    1284               0 :     for (PRUint32 i = index; i < length; ++i) {
    1285               0 :       nsGenericHTMLFormElement* currentControl = controls[i];
    1286               0 :       if (currentControl->IsSubmitControl()) {
    1287               0 :         *firstSubmitSlot = currentControl;
    1288               0 :         break;
    1289                 :       }
    1290                 :     }
    1291                 :   }
    1292                 : 
    1293               0 :   if (aChild == mDefaultSubmitElement) {
    1294                 :     // Need to reset mDefaultSubmitElement.  Do this asynchronously so
    1295                 :     // that we're not doing it while the DOM is in flux.
    1296               0 :     mDefaultSubmitElement = nsnull;
    1297               0 :     nsContentUtils::AddScriptRunner(new RemoveElementRunnable(this));
    1298                 : 
    1299                 :     // Note that we don't need to notify on the old default submit (which is
    1300                 :     // being removed) because it's either being removed from the DOM or
    1301                 :     // changing attributes in a way that makes it responsible for sending its
    1302                 :     // own notifications.
    1303                 :   }
    1304                 : 
    1305                 :   // If the element was subject to constraint validaton and is invalid, we need
    1306                 :   // to update our internal counter.
    1307               0 :   if (aUpdateValidity) {
    1308               0 :     nsCOMPtr<nsIConstraintValidation> cvElmt = do_QueryObject(aChild);
    1309               0 :     if (cvElmt &&
    1310               0 :         cvElmt->IsCandidateForConstraintValidation() && !cvElmt->IsValid()) {
    1311               0 :       UpdateValidity(true);
    1312                 :     }
    1313                 :   }
    1314                 : 
    1315               0 :   return rv;
    1316                 : }
    1317                 : 
    1318                 : void
    1319               0 : nsHTMLFormElement::HandleDefaultSubmitRemoval()
    1320                 : {
    1321               0 :   if (mDefaultSubmitElement) {
    1322                 :     // Already got reset somehow; nothing else to do here
    1323               0 :     return;
    1324                 :   }
    1325                 : 
    1326               0 :   if (!mFirstSubmitNotInElements) {
    1327               0 :     mDefaultSubmitElement = mFirstSubmitInElements;
    1328               0 :   } else if (!mFirstSubmitInElements) {
    1329               0 :     mDefaultSubmitElement = mFirstSubmitNotInElements;
    1330                 :   } else {
    1331               0 :     NS_ASSERTION(mFirstSubmitInElements != mFirstSubmitNotInElements,
    1332                 :                  "How did that happen?");
    1333                 :     // Have both; use the earlier one
    1334                 :     mDefaultSubmitElement =
    1335                 :       CompareFormControlPosition(mFirstSubmitInElements,
    1336               0 :                                  mFirstSubmitNotInElements, this) < 0 ?
    1337               0 :       mFirstSubmitInElements : mFirstSubmitNotInElements;
    1338                 :   }
    1339                 : 
    1340               0 :   NS_POSTCONDITION(mDefaultSubmitElement == mFirstSubmitInElements ||
    1341                 :                    mDefaultSubmitElement == mFirstSubmitNotInElements,
    1342                 :                    "What happened here?");
    1343                 : 
    1344                 :   // Notify about change if needed.
    1345               0 :   if (mDefaultSubmitElement) {
    1346               0 :     mDefaultSubmitElement->UpdateState(true);
    1347                 :   }
    1348                 : }
    1349                 : 
    1350                 : nsresult
    1351               0 : nsHTMLFormElement::RemoveElementFromTable(nsGenericHTMLFormElement* aElement,
    1352                 :                                           const nsAString& aName)
    1353                 : {
    1354               0 :   return mControls->RemoveElementFromTable(aElement, aName);
    1355                 : }
    1356                 : 
    1357                 : NS_IMETHODIMP_(already_AddRefed<nsISupports>)
    1358               0 : nsHTMLFormElement::ResolveName(const nsAString& aName)
    1359                 : {
    1360               0 :   return DoResolveName(aName, true);
    1361                 : }
    1362                 : 
    1363                 : already_AddRefed<nsISupports>
    1364               0 : nsHTMLFormElement::DoResolveName(const nsAString& aName,
    1365                 :                                  bool aFlushContent)
    1366                 : {
    1367                 :   nsISupports *result;
    1368               0 :   NS_IF_ADDREF(result = mControls->NamedItemInternal(aName, aFlushContent));
    1369               0 :   return result;
    1370                 : }
    1371                 : 
    1372                 : void
    1373               0 : nsHTMLFormElement::OnSubmitClickBegin(nsIContent* aOriginatingElement)
    1374                 : {
    1375               0 :   mDeferSubmission = true;
    1376                 : 
    1377                 :   // Prepare to run NotifySubmitObservers early before the
    1378                 :   // scripts on the page get to modify the form data, possibly
    1379                 :   // throwing off any password manager. (bug 257781)
    1380               0 :   nsCOMPtr<nsIURI> actionURI;
    1381                 :   nsresult rv;
    1382                 : 
    1383               0 :   rv = GetActionURL(getter_AddRefs(actionURI), aOriginatingElement);
    1384               0 :   if (NS_FAILED(rv) || !actionURI)
    1385                 :     return;
    1386                 : 
    1387                 :   // Notify observers of submit if the form is valid.
    1388                 :   // TODO: checking for mInvalidElementsCount is a temporary fix that should be
    1389                 :   // removed with bug 610402.
    1390               0 :   if (mInvalidElementsCount == 0) {
    1391               0 :     bool cancelSubmit = false;
    1392               0 :     rv = NotifySubmitObservers(actionURI, &cancelSubmit, true);
    1393               0 :     if (NS_SUCCEEDED(rv)) {
    1394               0 :       mNotifiedObservers = true;
    1395               0 :       mNotifiedObserversResult = cancelSubmit;
    1396                 :     }
    1397                 :   }
    1398                 : }
    1399                 : 
    1400                 : void
    1401               0 : nsHTMLFormElement::OnSubmitClickEnd()
    1402                 : {
    1403               0 :   mDeferSubmission = false;
    1404               0 : }
    1405                 : 
    1406                 : void
    1407               0 : nsHTMLFormElement::FlushPendingSubmission()
    1408                 : {
    1409               0 :   if (mPendingSubmission) {
    1410                 :     // Transfer owning reference so that the submissioin doesn't get deleted
    1411                 :     // if we reenter
    1412               0 :     nsAutoPtr<nsFormSubmission> submission = mPendingSubmission;
    1413                 : 
    1414               0 :     SubmitSubmission(submission);
    1415                 :   }
    1416               0 : }
    1417                 : 
    1418                 : nsresult
    1419               0 : nsHTMLFormElement::GetActionURL(nsIURI** aActionURL,
    1420                 :                                 nsIContent* aOriginatingElement)
    1421                 : {
    1422               0 :   nsresult rv = NS_OK;
    1423                 : 
    1424               0 :   *aActionURL = nsnull;
    1425                 : 
    1426                 :   //
    1427                 :   // Grab the URL string
    1428                 :   //
    1429                 :   // If the originating element is a submit control and has the formaction
    1430                 :   // attribute specified, it should be used. Otherwise, the action attribute
    1431                 :   // from the form element should be used.
    1432                 :   //
    1433               0 :   nsAutoString action;
    1434                 : 
    1435               0 :   if (aOriginatingElement &&
    1436               0 :       aOriginatingElement->HasAttr(kNameSpaceID_None, nsGkAtoms::formaction)) {
    1437                 : #ifdef DEBUG
    1438               0 :     nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(aOriginatingElement);
    1439               0 :     NS_ASSERTION(formControl && formControl->IsSubmitControl(),
    1440                 :                  "The originating element must be a submit form control!");
    1441                 : #endif // DEBUG
    1442                 : 
    1443               0 :     nsCOMPtr<nsIDOMHTMLInputElement> inputElement = do_QueryInterface(aOriginatingElement);
    1444               0 :     if (inputElement) {
    1445               0 :       inputElement->GetFormAction(action);
    1446                 :     } else {
    1447               0 :       nsCOMPtr<nsIDOMHTMLButtonElement> buttonElement = do_QueryInterface(aOriginatingElement);
    1448               0 :       if (buttonElement) {
    1449               0 :         buttonElement->GetFormAction(action);
    1450                 :       } else {
    1451               0 :         NS_ERROR("Originating element must be an input or button element!");
    1452               0 :         return NS_ERROR_UNEXPECTED;
    1453                 :       }
    1454                 :     }
    1455                 :   } else {
    1456               0 :     GetAction(action);
    1457                 :   }
    1458                 : 
    1459                 :   //
    1460                 :   // Form the full action URL
    1461                 :   //
    1462                 : 
    1463                 :   // Get the document to form the URL.
    1464                 :   // We'll also need it later to get the DOM window when notifying form submit
    1465                 :   // observers (bug 33203)
    1466               0 :   if (!IsInDoc()) {
    1467               0 :     return NS_OK; // No doc means don't submit, see Bug 28988
    1468                 :   }
    1469                 : 
    1470                 :   // Get base URL
    1471               0 :   nsIDocument *document = OwnerDoc();
    1472               0 :   nsIURI *docURI = document->GetDocumentURI();
    1473               0 :   NS_ENSURE_TRUE(docURI, NS_ERROR_UNEXPECTED);
    1474                 : 
    1475                 :   // If an action is not specified and we are inside
    1476                 :   // a HTML document then reload the URL. This makes us
    1477                 :   // compatible with 4.x browsers.
    1478                 :   // If we are in some other type of document such as XML or
    1479                 :   // XUL, do nothing. This prevents undesirable reloading of
    1480                 :   // a document inside XUL.
    1481                 : 
    1482               0 :   nsCOMPtr<nsIURI> actionURL;
    1483               0 :   if (action.IsEmpty()) {
    1484               0 :     nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(document));
    1485               0 :     if (!htmlDoc) {
    1486                 :       // Must be a XML, XUL or other non-HTML document type
    1487                 :       // so do nothing.
    1488               0 :       return NS_OK;
    1489                 :     }
    1490                 : 
    1491               0 :     rv = docURI->Clone(getter_AddRefs(actionURL));
    1492               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1493                 :   } else {
    1494               0 :     nsCOMPtr<nsIURI> baseURL = GetBaseURI();
    1495               0 :     NS_ASSERTION(baseURL, "No Base URL found in Form Submit!\n");
    1496               0 :     if (!baseURL) {
    1497               0 :       return NS_OK; // No base URL -> exit early, see Bug 30721
    1498                 :     }
    1499               0 :     rv = NS_NewURI(getter_AddRefs(actionURL), action, nsnull, baseURL);
    1500               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1501                 :   }
    1502                 : 
    1503                 :   //
    1504                 :   // Verify the URL should be reached
    1505                 :   //
    1506                 :   // Get security manager, check to see if access to action URI is allowed.
    1507                 :   //
    1508                 :   nsIScriptSecurityManager *securityManager =
    1509               0 :       nsContentUtils::GetSecurityManager();
    1510                 :   rv = securityManager->
    1511                 :     CheckLoadURIWithPrincipal(NodePrincipal(), actionURL,
    1512               0 :                               nsIScriptSecurityManager::STANDARD);
    1513               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1514                 : 
    1515                 :   //
    1516                 :   // Assign to the output
    1517                 :   //
    1518               0 :   *aActionURL = actionURL;
    1519               0 :   NS_ADDREF(*aActionURL);
    1520                 : 
    1521               0 :   return rv;
    1522                 : }
    1523                 : 
    1524                 : NS_IMETHODIMP_(nsIFormControl*)
    1525               0 : nsHTMLFormElement::GetDefaultSubmitElement() const
    1526                 : {
    1527               0 :   NS_PRECONDITION(mDefaultSubmitElement == mFirstSubmitInElements ||
    1528                 :                   mDefaultSubmitElement == mFirstSubmitNotInElements,
    1529                 :                   "What happened here?");
    1530                 :   
    1531               0 :   return mDefaultSubmitElement;
    1532                 : }
    1533                 : 
    1534                 : bool
    1535               0 : nsHTMLFormElement::IsDefaultSubmitElement(const nsIFormControl* aControl) const
    1536                 : {
    1537               0 :   NS_PRECONDITION(aControl, "Unexpected call");
    1538                 : 
    1539               0 :   if (aControl == mDefaultSubmitElement) {
    1540                 :     // Yes, it is
    1541               0 :     return true;
    1542                 :   }
    1543                 : 
    1544               0 :   if (mDefaultSubmitElement ||
    1545               0 :       (aControl != mFirstSubmitInElements &&
    1546               0 :        aControl != mFirstSubmitNotInElements)) {
    1547                 :     // It isn't
    1548               0 :     return false;
    1549                 :   }
    1550                 : 
    1551                 :   // mDefaultSubmitElement is null, but we have a non-null submit around
    1552                 :   // (aControl, in fact).  figure out whether it's in fact the default submit
    1553                 :   // and just hasn't been set that way yet.  Note that we can't just call
    1554                 :   // HandleDefaultSubmitRemoval because we might need to notify to handle that
    1555                 :   // correctly and we don't know whether that's safe right here.
    1556               0 :   if (!mFirstSubmitInElements || !mFirstSubmitNotInElements) {
    1557                 :     // We only have one first submit; aControl has to be it
    1558               0 :     return true;
    1559                 :   }
    1560                 : 
    1561                 :   // We have both kinds of submits.  Check which comes first.
    1562                 :   nsIFormControl* defaultSubmit =
    1563                 :     CompareFormControlPosition(mFirstSubmitInElements,
    1564               0 :                                mFirstSubmitNotInElements, this) < 0 ?
    1565               0 :       mFirstSubmitInElements : mFirstSubmitNotInElements;
    1566               0 :   return aControl == defaultSubmit;
    1567                 : }
    1568                 : 
    1569                 : bool
    1570               0 : nsHTMLFormElement::HasSingleTextControl() const
    1571                 : {
    1572                 :   // Input text controls are always in the elements list.
    1573               0 :   PRUint32 numTextControlsFound = 0;
    1574               0 :   PRUint32 length = mControls->mElements.Length();
    1575               0 :   for (PRUint32 i = 0; i < length && numTextControlsFound < 2; ++i) {
    1576               0 :     if (mControls->mElements[i]->IsSingleLineTextControl(false)) {
    1577               0 :       numTextControlsFound++;
    1578                 :     }
    1579                 :   }
    1580               0 :   return numTextControlsFound == 1;
    1581                 : }
    1582                 : 
    1583                 : NS_IMETHODIMP
    1584               0 : nsHTMLFormElement::GetEncoding(nsAString& aEncoding)
    1585                 : {
    1586               0 :   return GetEnctype(aEncoding);
    1587                 : }
    1588                 :  
    1589                 : NS_IMETHODIMP
    1590               0 : nsHTMLFormElement::SetEncoding(const nsAString& aEncoding)
    1591                 : {
    1592               0 :   return SetEnctype(aEncoding);
    1593                 : }
    1594                 : 
    1595                 : NS_IMETHODIMP    
    1596               0 : nsHTMLFormElement::GetLength(PRInt32* aLength)
    1597                 : {
    1598                 :   PRUint32 length;
    1599               0 :   nsresult rv = mControls->GetLength(&length);
    1600               0 :   *aLength = length;
    1601               0 :   return rv;
    1602                 : }
    1603                 : 
    1604                 : void
    1605               0 : nsHTMLFormElement::ForgetCurrentSubmission()
    1606                 : {
    1607               0 :   mNotifiedObservers = false;
    1608               0 :   mIsSubmitting = false;
    1609               0 :   mSubmittingRequest = nsnull;
    1610               0 :   nsCOMPtr<nsIWebProgress> webProgress = do_QueryReferent(mWebProgress);
    1611               0 :   if (webProgress) {
    1612               0 :     webProgress->RemoveProgressListener(this);
    1613                 :   }
    1614               0 :   mWebProgress = nsnull;
    1615               0 : }
    1616                 : 
    1617                 : bool
    1618               0 : nsHTMLFormElement::CheckFormValidity(nsIMutableArray* aInvalidElements) const
    1619                 : {
    1620               0 :   bool ret = true;
    1621                 : 
    1622               0 :   nsTArray<nsGenericHTMLFormElement*> sortedControls;
    1623               0 :   if (NS_FAILED(mControls->GetSortedControls(sortedControls))) {
    1624               0 :     return false;
    1625                 :   }
    1626                 : 
    1627               0 :   PRUint32 len = sortedControls.Length();
    1628                 : 
    1629                 :   // Hold a reference to the elements so they can't be deleted while calling
    1630                 :   // the invalid events.
    1631               0 :   for (PRUint32 i = 0; i < len; ++i) {
    1632               0 :     static_cast<nsGenericHTMLElement*>(sortedControls[i])->AddRef();
    1633                 :   }
    1634                 : 
    1635               0 :   for (PRUint32 i = 0; i < len; ++i) {
    1636                 :     nsCOMPtr<nsIConstraintValidation> cvElmt =
    1637               0 :       do_QueryInterface((nsGenericHTMLElement*)sortedControls[i]);
    1638               0 :     if (cvElmt && cvElmt->IsCandidateForConstraintValidation() &&
    1639               0 :         !cvElmt->IsValid()) {
    1640               0 :       ret = false;
    1641               0 :       bool defaultAction = true;
    1642               0 :       nsContentUtils::DispatchTrustedEvent(sortedControls[i]->OwnerDoc(),
    1643               0 :                                            static_cast<nsIContent*>(sortedControls[i]),
    1644               0 :                                            NS_LITERAL_STRING("invalid"),
    1645               0 :                                            false, true, &defaultAction);
    1646                 : 
    1647                 :       // Add all unhandled invalid controls to aInvalidElements if the caller
    1648                 :       // requested them.
    1649               0 :       if (defaultAction && aInvalidElements) {
    1650               0 :         aInvalidElements->AppendElement((nsGenericHTMLElement*)sortedControls[i],
    1651               0 :                                         false);
    1652                 :       }
    1653                 :     }
    1654                 :   }
    1655                 : 
    1656                 :   // Release the references.
    1657               0 :   for (PRUint32 i = 0; i < len; ++i) {
    1658               0 :     static_cast<nsGenericHTMLElement*>(sortedControls[i])->Release();
    1659                 :   }
    1660                 : 
    1661               0 :   return ret;
    1662                 : }
    1663                 : 
    1664                 : bool
    1665               0 : nsHTMLFormElement::CheckValidFormSubmission()
    1666                 : {
    1667                 :   /**
    1668                 :    * Check for form validity: do not submit a form if there are unhandled
    1669                 :    * invalid controls in the form.
    1670                 :    * This should not be done if the form has been submitted with .submit().
    1671                 :    *
    1672                 :    * NOTE: for the moment, we are also checking that there is an observer for
    1673                 :    * NS_INVALIDFORMSUBMIT_SUBJECT so it will prevent blocking form submission
    1674                 :    * if the browser does not have implemented a UI yet.
    1675                 :    *
    1676                 :    * TODO: the check for observer should be removed later when HTML5 Forms will
    1677                 :    * be spread enough and authors will assume forms can't be submitted when
    1678                 :    * invalid. See bug 587671.
    1679                 :    */
    1680                 : 
    1681               0 :   NS_ASSERTION(!HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate),
    1682                 :                "We shouldn't be there if novalidate is set!");
    1683                 : 
    1684                 :   // When .submit() is called aEvent = nsnull so we can rely on that to know if
    1685                 :   // we have to check the validity of the form.
    1686                 :   nsCOMPtr<nsIObserverService> service =
    1687               0 :     mozilla::services::GetObserverService();
    1688               0 :   if (!service) {
    1689               0 :     NS_WARNING("No observer service available!");
    1690               0 :     return true;
    1691                 :   }
    1692                 : 
    1693               0 :   nsCOMPtr<nsISimpleEnumerator> theEnum;
    1694               0 :   nsresult rv = service->EnumerateObservers(NS_INVALIDFORMSUBMIT_SUBJECT,
    1695               0 :                                             getter_AddRefs(theEnum));
    1696               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1697                 : 
    1698               0 :   bool hasObserver = false;
    1699               0 :   rv = theEnum->HasMoreElements(&hasObserver);
    1700                 : 
    1701                 :   // Do not check form validity if there is no observer for
    1702                 :   // NS_INVALIDFORMSUBMIT_SUBJECT.
    1703               0 :   if (NS_SUCCEEDED(rv) && hasObserver) {
    1704                 :     nsCOMPtr<nsIMutableArray> invalidElements =
    1705               0 :       do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
    1706               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1707                 : 
    1708               0 :     if (!CheckFormValidity(invalidElements.get())) {
    1709                 :       // For the first invalid submission, we should update element states.
    1710                 :       // We have to do that _before_ calling the observers so we are sure they
    1711                 :       // will not interfere (like focusing the element).
    1712               0 :       if (!mEverTriedInvalidSubmit) {
    1713               0 :         mEverTriedInvalidSubmit = true;
    1714                 : 
    1715                 :         /*
    1716                 :          * We are going to call update states assuming elements want to
    1717                 :          * be notified because we can't know.
    1718                 :          * Submissions shouldn't happen during parsing so it _should_ be safe.
    1719                 :          */
    1720                 : 
    1721               0 :         nsAutoScriptBlocker scriptBlocker;
    1722                 : 
    1723               0 :         for (PRUint32 i = 0, length = mControls->mElements.Length();
    1724                 :              i < length; ++i) {
    1725                 :           // Input elements can trigger a form submission and we want to
    1726                 :           // update the style in that case.
    1727               0 :           if (mControls->mElements[i]->IsHTML(nsGkAtoms::input) &&
    1728               0 :               nsContentUtils::IsFocusedContent(mControls->mElements[i])) {
    1729               0 :             static_cast<nsHTMLInputElement*>(mControls->mElements[i])
    1730               0 :               ->UpdateValidityUIBits(true);
    1731                 :           }
    1732                 : 
    1733               0 :           mControls->mElements[i]->UpdateState(true);
    1734                 :         }
    1735                 : 
    1736                 :         // Because of backward compatibility, <input type='image'> is not in
    1737                 :         // elements but can be invalid.
    1738                 :         // TODO: should probably be removed when bug 606491 will be fixed.
    1739               0 :         for (PRUint32 i = 0, length = mControls->mNotInElements.Length();
    1740                 :              i < length; ++i) {
    1741               0 :           mControls->mNotInElements[i]->UpdateState(true);
    1742                 :         }
    1743                 :       }
    1744                 : 
    1745               0 :       nsCOMPtr<nsISupports> inst;
    1746               0 :       nsCOMPtr<nsIFormSubmitObserver> observer;
    1747               0 :       bool more = true;
    1748               0 :       while (NS_SUCCEEDED(theEnum->HasMoreElements(&more)) && more) {
    1749               0 :         theEnum->GetNext(getter_AddRefs(inst));
    1750               0 :         observer = do_QueryInterface(inst);
    1751                 : 
    1752               0 :         if (observer) {
    1753               0 :           observer->NotifyInvalidSubmit(this,
    1754               0 :                                         static_cast<nsIArray*>(invalidElements));
    1755                 :         }
    1756                 :       }
    1757                 : 
    1758                 :       // The form is invalid. Observers have been alerted. Do not submit.
    1759               0 :       return false;
    1760               0 :     }
    1761                 :   } else {
    1762                 :     NS_WARNING("There is no observer for \"invalidformsubmit\". \
    1763               0 : One should be implemented!");
    1764                 :   }
    1765                 : 
    1766               0 :   return true;
    1767                 : }
    1768                 : 
    1769                 : void
    1770               0 : nsHTMLFormElement::UpdateValidity(bool aElementValidity)
    1771                 : {
    1772               0 :   if (aElementValidity) {
    1773               0 :     --mInvalidElementsCount;
    1774                 :   } else {
    1775               0 :     ++mInvalidElementsCount;
    1776                 :   }
    1777                 : 
    1778               0 :   NS_ASSERTION(mInvalidElementsCount >= 0, "Something went seriously wrong!");
    1779                 : 
    1780                 :   // The form validity has just changed if:
    1781                 :   // - there are no more invalid elements ;
    1782                 :   // - or there is one invalid elmement and an element just became invalid.
    1783                 :   // If we have invalid elements and we used to before as well, do nothing.
    1784               0 :   if (mInvalidElementsCount &&
    1785                 :       (mInvalidElementsCount != 1 || aElementValidity)) {
    1786               0 :     return;
    1787                 :   }
    1788                 : 
    1789                 :   /*
    1790                 :    * We are going to update states assuming submit controls want to
    1791                 :    * be notified because we can't know.
    1792                 :    * UpdateValidity shouldn't be called so much during parsing so it _should_
    1793                 :    * be safe.
    1794                 :    */
    1795                 : 
    1796               0 :   nsAutoScriptBlocker scriptBlocker;
    1797                 : 
    1798                 :   // Inform submit controls that the form validity has changed.
    1799               0 :   for (PRUint32 i = 0, length = mControls->mElements.Length();
    1800                 :        i < length; ++i) {
    1801               0 :     if (mControls->mElements[i]->IsSubmitControl()) {
    1802               0 :       mControls->mElements[i]->UpdateState(true);
    1803                 :     }
    1804                 :   }
    1805                 : 
    1806                 :   // Because of backward compatibility, <input type='image'> is not in elements
    1807                 :   // so we have to check for controls not in elements too.
    1808               0 :   PRUint32 length = mControls->mNotInElements.Length();
    1809               0 :   for (PRUint32 i = 0; i < length; ++i) {
    1810               0 :     if (mControls->mNotInElements[i]->IsSubmitControl()) {
    1811               0 :       mControls->mNotInElements[i]->UpdateState(true);
    1812                 :     }
    1813                 :   }
    1814                 : 
    1815               0 :   UpdateState(true);
    1816                 : }
    1817                 : 
    1818                 : // nsIWebProgressListener
    1819                 : NS_IMETHODIMP
    1820               0 : nsHTMLFormElement::OnStateChange(nsIWebProgress* aWebProgress,
    1821                 :                                  nsIRequest* aRequest,
    1822                 :                                  PRUint32 aStateFlags,
    1823                 :                                  PRUint32 aStatus)
    1824                 : {
    1825                 :   // If STATE_STOP is never fired for any reason (redirect?  Failed state
    1826                 :   // change?) the form element will leak.  It will be kept around by the
    1827                 :   // nsIWebProgressListener (assuming it keeps a strong pointer).  We will
    1828                 :   // consequently leak the request.
    1829               0 :   if (aRequest == mSubmittingRequest &&
    1830                 :       aStateFlags & nsIWebProgressListener::STATE_STOP) {
    1831               0 :     ForgetCurrentSubmission();
    1832                 :   }
    1833                 : 
    1834               0 :   return NS_OK;
    1835                 : }
    1836                 : 
    1837                 : NS_IMETHODIMP
    1838               0 : nsHTMLFormElement::OnProgressChange(nsIWebProgress* aWebProgress,
    1839                 :                                     nsIRequest* aRequest,
    1840                 :                                     PRInt32 aCurSelfProgress,
    1841                 :                                     PRInt32 aMaxSelfProgress,
    1842                 :                                     PRInt32 aCurTotalProgress,
    1843                 :                                     PRInt32 aMaxTotalProgress)
    1844                 : {
    1845               0 :   NS_NOTREACHED("notification excluded in AddProgressListener(...)");
    1846               0 :   return NS_OK;
    1847                 : }
    1848                 : 
    1849                 : NS_IMETHODIMP
    1850               0 : nsHTMLFormElement::OnLocationChange(nsIWebProgress* aWebProgress,
    1851                 :                                     nsIRequest* aRequest,
    1852                 :                                     nsIURI* location,
    1853                 :                                     PRUint32 aFlags)
    1854                 : {
    1855               0 :   NS_NOTREACHED("notification excluded in AddProgressListener(...)");
    1856               0 :   return NS_OK;
    1857                 : }
    1858                 : 
    1859                 : NS_IMETHODIMP
    1860               0 : nsHTMLFormElement::OnStatusChange(nsIWebProgress* aWebProgress,
    1861                 :                                   nsIRequest* aRequest,
    1862                 :                                   nsresult aStatus,
    1863                 :                                   const PRUnichar* aMessage)
    1864                 : {
    1865               0 :   NS_NOTREACHED("notification excluded in AddProgressListener(...)");
    1866               0 :   return NS_OK;
    1867                 : }
    1868                 : 
    1869                 : NS_IMETHODIMP
    1870               0 : nsHTMLFormElement::OnSecurityChange(nsIWebProgress* aWebProgress,
    1871                 :                                     nsIRequest* aRequest,
    1872                 :                                     PRUint32 state)
    1873                 : {
    1874               0 :   NS_NOTREACHED("notification excluded in AddProgressListener(...)");
    1875               0 :   return NS_OK;
    1876                 : }
    1877                 :  
    1878                 : NS_IMETHODIMP_(PRInt32)
    1879               0 : nsHTMLFormElement::IndexOfControl(nsIFormControl* aControl)
    1880                 : {
    1881               0 :   PRInt32 index = nsnull;
    1882               0 :   return mControls->IndexOfControl(aControl, &index) == NS_OK ? index : nsnull;
    1883                 : }
    1884                 : 
    1885                 : NS_IMETHODIMP
    1886               0 : nsHTMLFormElement::SetCurrentRadioButton(const nsAString& aName,
    1887                 :                                          nsIDOMHTMLInputElement* aRadio)
    1888                 : {
    1889               0 :   NS_ENSURE_TRUE(mSelectedRadioButtons.Put(aName, aRadio),
    1890                 :                  NS_ERROR_OUT_OF_MEMORY);
    1891                 : 
    1892               0 :   return NS_OK;
    1893                 : }
    1894                 : 
    1895                 : NS_IMETHODIMP
    1896               0 : nsHTMLFormElement::GetCurrentRadioButton(const nsAString& aName,
    1897                 :                                          nsIDOMHTMLInputElement** aRadio)
    1898                 : {
    1899               0 :   mSelectedRadioButtons.Get(aName, aRadio);
    1900                 : 
    1901               0 :   return NS_OK;
    1902                 : }
    1903                 : 
    1904                 : NS_IMETHODIMP
    1905               0 : nsHTMLFormElement::GetPositionInGroup(nsIDOMHTMLInputElement *aRadio,
    1906                 :                                       PRInt32 *aPositionIndex,
    1907                 :                                       PRInt32 *aItemsInGroup)
    1908                 : {
    1909               0 :   *aPositionIndex = 0;
    1910               0 :   *aItemsInGroup = 1;
    1911                 : 
    1912               0 :   nsAutoString name;
    1913               0 :   aRadio->GetName(name);
    1914               0 :   if (name.IsEmpty()) {
    1915               0 :     return NS_OK;
    1916                 :   }
    1917                 : 
    1918               0 :   nsCOMPtr<nsISupports> itemWithName;
    1919               0 :   itemWithName = ResolveName(name);
    1920               0 :   NS_ENSURE_TRUE(itemWithName, NS_ERROR_FAILURE);
    1921               0 :   nsCOMPtr<nsINodeList> radioGroup(do_QueryInterface(itemWithName));
    1922                 : 
    1923               0 :   NS_ASSERTION(radioGroup, "No such radio group in this container");
    1924               0 :   if (!radioGroup) {
    1925               0 :     return NS_OK;
    1926                 :   }
    1927                 : 
    1928               0 :   nsCOMPtr<nsIContent> currentRadioNode(do_QueryInterface(aRadio));
    1929               0 :   NS_ASSERTION(currentRadioNode, "No nsIContent for current radio button");
    1930               0 :   *aPositionIndex = radioGroup->IndexOf(currentRadioNode);
    1931               0 :   NS_ASSERTION(*aPositionIndex >= 0, "Radio button not found in its own group");
    1932                 :   PRUint32 itemsInGroup;
    1933               0 :   radioGroup->GetLength(&itemsInGroup);
    1934               0 :   *aItemsInGroup = itemsInGroup;
    1935                 : 
    1936               0 :   return NS_OK;
    1937                 : }
    1938                 : 
    1939                 : NS_IMETHODIMP
    1940               0 : nsHTMLFormElement::GetNextRadioButton(const nsAString& aName,
    1941                 :                                       const bool aPrevious,
    1942                 :                                       nsIDOMHTMLInputElement*  aFocusedRadio,
    1943                 :                                       nsIDOMHTMLInputElement** aRadioOut)
    1944                 : {
    1945                 :   // Return the radio button relative to the focused radio button.
    1946                 :   // If no radio is focused, get the radio relative to the selected one.
    1947               0 :   *aRadioOut = nsnull;
    1948                 : 
    1949               0 :   nsCOMPtr<nsIDOMHTMLInputElement> currentRadio;
    1950               0 :   if (aFocusedRadio) {
    1951               0 :     currentRadio = aFocusedRadio;
    1952                 :   }
    1953                 :   else {
    1954               0 :     mSelectedRadioButtons.Get(aName, getter_AddRefs(currentRadio));
    1955                 :   }
    1956                 : 
    1957               0 :   nsCOMPtr<nsISupports> itemWithName = ResolveName(aName);
    1958               0 :   nsCOMPtr<nsINodeList> radioGroup(do_QueryInterface(itemWithName));
    1959                 : 
    1960               0 :   if (!radioGroup) {
    1961               0 :     return NS_ERROR_FAILURE;
    1962                 :   }
    1963                 : 
    1964               0 :   nsCOMPtr<nsIContent> currentRadioNode(do_QueryInterface(currentRadio));
    1965               0 :   NS_ASSERTION(currentRadioNode, "No nsIContent for current radio button");
    1966               0 :   PRInt32 index = radioGroup->IndexOf(currentRadioNode);
    1967               0 :   if (index < 0) {
    1968               0 :     return NS_ERROR_FAILURE;
    1969                 :   }
    1970                 : 
    1971                 :   PRUint32 numRadios;
    1972               0 :   radioGroup->GetLength(&numRadios);
    1973               0 :   bool disabled = true;
    1974               0 :   nsCOMPtr<nsIDOMHTMLInputElement> radio;
    1975               0 :   nsCOMPtr<nsIFormControl> formControl;
    1976                 : 
    1977               0 :   do {
    1978               0 :     if (aPrevious) {
    1979               0 :       if (--index < 0) {
    1980               0 :         index = numRadios -1;
    1981                 :       }
    1982                 :     }
    1983               0 :     else if (++index >= (PRInt32)numRadios) {
    1984               0 :       index = 0;
    1985                 :     }
    1986               0 :     radio = do_QueryInterface(radioGroup->GetNodeAt(index));
    1987               0 :     if (!radio)
    1988               0 :       continue;
    1989                 : 
    1990                 :     // XXXbz why is this formControl check needed, exactly?
    1991               0 :     formControl = do_QueryInterface(radio);
    1992               0 :     if (!formControl || formControl->GetType() != NS_FORM_INPUT_RADIO)
    1993               0 :       continue;
    1994                 : 
    1995               0 :     radio->GetDisabled(&disabled);
    1996               0 :   } while (disabled && radio != currentRadio);
    1997                 : 
    1998               0 :   NS_IF_ADDREF(*aRadioOut = radio);
    1999               0 :   return NS_OK;
    2000                 : }
    2001                 : 
    2002                 : NS_IMETHODIMP
    2003               0 : nsHTMLFormElement::WalkRadioGroup(const nsAString& aName,
    2004                 :                                   nsIRadioVisitor* aVisitor,
    2005                 :                                   bool aFlushContent)
    2006                 : {
    2007               0 :   if (aName.IsEmpty()) {
    2008                 :     //
    2009                 :     // XXX If the name is empty, it's not stored in the control list.  There
    2010                 :     // *must* be a more efficient way to do this.
    2011                 :     //
    2012               0 :     nsCOMPtr<nsIFormControl> control;
    2013               0 :     PRUint32 len = GetElementCount();
    2014               0 :     for (PRUint32 i = 0; i < len; i++) {
    2015               0 :       control = GetElementAt(i);
    2016               0 :       if (control->GetType() == NS_FORM_INPUT_RADIO) {
    2017               0 :         nsCOMPtr<nsIContent> controlContent = do_QueryInterface(control);
    2018               0 :         if (controlContent &&
    2019               0 :             controlContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
    2020               0 :                                         EmptyString(), eCaseMatters) &&
    2021               0 :             !aVisitor->Visit(control)) {
    2022                 :           break;
    2023                 :         }
    2024                 :       }
    2025                 :     }
    2026               0 :     return NS_OK;
    2027                 :   }
    2028                 : 
    2029                 :   // Get the control / list of controls from the form using form["name"]
    2030               0 :   nsCOMPtr<nsISupports> item = DoResolveName(aName, aFlushContent);
    2031               0 :   if (!item) {
    2032               0 :     return NS_ERROR_FAILURE;
    2033                 :   }
    2034                 : 
    2035                 :   // If it's just a lone radio button, then select it.
    2036               0 :   nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(item);
    2037               0 :   if (formControl) {
    2038               0 :     if (formControl->GetType() == NS_FORM_INPUT_RADIO) {
    2039               0 :       aVisitor->Visit(formControl);
    2040                 :     }
    2041               0 :     return NS_OK;
    2042                 :   }
    2043                 : 
    2044               0 :   nsCOMPtr<nsIDOMNodeList> nodeList = do_QueryInterface(item);
    2045               0 :   if (!nodeList) {
    2046               0 :     return NS_OK;
    2047                 :   }
    2048               0 :   PRUint32 length = 0;
    2049               0 :   nodeList->GetLength(&length);
    2050               0 :   for (PRUint32 i = 0; i < length; i++) {
    2051               0 :     nsCOMPtr<nsIDOMNode> node;
    2052               0 :     nodeList->Item(i, getter_AddRefs(node));
    2053               0 :     nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(node);
    2054               0 :     if (formControl && formControl->GetType() == NS_FORM_INPUT_RADIO &&
    2055               0 :         !aVisitor->Visit(formControl)) {
    2056                 :       break;
    2057                 :     }
    2058                 :   }
    2059               0 :   return NS_OK;
    2060                 : }
    2061                 : 
    2062                 : NS_IMETHODIMP
    2063               0 : nsHTMLFormElement::AddToRadioGroup(const nsAString& aName,
    2064                 :                                    nsIFormControl* aRadio)
    2065                 : {
    2066               0 :   nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
    2067               0 :   NS_ASSERTION(element, "radio controls have to be content elements!");
    2068                 : 
    2069               0 :   if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
    2070                 :     mRequiredRadioButtonCounts.Put(aName,
    2071               0 :                                    mRequiredRadioButtonCounts.Get(aName)+1);
    2072                 :   }
    2073                 : 
    2074               0 :   return NS_OK;
    2075                 : }
    2076                 : 
    2077                 : NS_IMETHODIMP
    2078               0 : nsHTMLFormElement::RemoveFromRadioGroup(const nsAString& aName,
    2079                 :                                         nsIFormControl* aRadio)
    2080                 : {
    2081               0 :   nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
    2082               0 :   NS_ASSERTION(element, "radio controls have to be content elements!");
    2083                 : 
    2084               0 :   if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
    2085               0 :     PRUint32 requiredNb = mRequiredRadioButtonCounts.Get(aName);
    2086               0 :     NS_ASSERTION(requiredNb >= 1,
    2087                 :                  "At least one radio button has to be required!");
    2088                 : 
    2089               0 :     if (requiredNb == 1) {
    2090               0 :       mRequiredRadioButtonCounts.Remove(aName);
    2091                 :     } else {
    2092               0 :       mRequiredRadioButtonCounts.Put(aName, requiredNb-1);
    2093                 :     }
    2094                 :   }
    2095                 : 
    2096               0 :   return NS_OK;
    2097                 : }
    2098                 : 
    2099                 : PRUint32
    2100               0 : nsHTMLFormElement::GetRequiredRadioCount(const nsAString& aName) const
    2101                 : {
    2102               0 :   return mRequiredRadioButtonCounts.Get(aName);
    2103                 : }
    2104                 : 
    2105                 : void
    2106               0 : nsHTMLFormElement::RadioRequiredChanged(const nsAString& aName,
    2107                 :                                         nsIFormControl* aRadio)
    2108                 : {
    2109               0 :   nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
    2110               0 :   NS_ASSERTION(element, "radio controls have to be content elements!");
    2111                 : 
    2112               0 :   if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
    2113                 :     mRequiredRadioButtonCounts.Put(aName,
    2114               0 :                                    mRequiredRadioButtonCounts.Get(aName)+1);
    2115                 :   } else {
    2116               0 :     PRUint32 requiredNb = mRequiredRadioButtonCounts.Get(aName);
    2117               0 :     NS_ASSERTION(requiredNb >= 1,
    2118                 :                  "At least one radio button has to be required!");
    2119               0 :     if (requiredNb == 1) {
    2120               0 :       mRequiredRadioButtonCounts.Remove(aName);
    2121                 :     } else {
    2122               0 :       mRequiredRadioButtonCounts.Put(aName, requiredNb-1);
    2123                 :     }
    2124                 :   }
    2125               0 : }
    2126                 : 
    2127                 : bool
    2128               0 : nsHTMLFormElement::GetValueMissingState(const nsAString& aName) const
    2129                 : {
    2130               0 :   return mValueMissingRadioGroups.Get(aName);
    2131                 : }
    2132                 : 
    2133                 : void
    2134               0 : nsHTMLFormElement::SetValueMissingState(const nsAString& aName, bool aValue)
    2135                 : {
    2136               0 :   mValueMissingRadioGroups.Put(aName, aValue);
    2137               0 : }
    2138                 : 
    2139                 : nsEventStates
    2140               0 : nsHTMLFormElement::IntrinsicState() const
    2141                 : {
    2142               0 :   nsEventStates state = nsGenericHTMLElement::IntrinsicState();
    2143                 : 
    2144               0 :   if (mInvalidElementsCount) {
    2145               0 :     state |= NS_EVENT_STATE_INVALID;
    2146                 :   } else {
    2147               0 :       state |= NS_EVENT_STATE_VALID;
    2148                 :   }
    2149                 : 
    2150                 :   return state;
    2151                 : }
    2152                 : 
    2153                 : //----------------------------------------------------------------------
    2154                 : // nsFormControlList implementation, this could go away if there were
    2155                 : // a lightweight collection implementation somewhere
    2156                 : 
    2157               0 : nsFormControlList::nsFormControlList(nsHTMLFormElement* aForm) :
    2158                 :   mForm(aForm),
    2159                 :   // Initialize the elements list to have an initial capacity
    2160                 :   // of 8 to reduce allocations on small forms.
    2161               0 :   mElements(8)
    2162                 : {
    2163                 :   // Mark ourselves as a proxy
    2164               0 :   SetIsProxy();
    2165               0 : }
    2166                 : 
    2167               0 : nsFormControlList::~nsFormControlList()
    2168                 : {
    2169               0 :   mForm = nsnull;
    2170               0 :   Clear();
    2171               0 : }
    2172                 : 
    2173               0 : nsresult nsFormControlList::Init()
    2174                 : {
    2175               0 :   NS_ENSURE_TRUE(
    2176                 :     mNameLookupTable.Init(NS_FORM_CONTROL_LIST_HASHTABLE_SIZE),
    2177                 :     NS_ERROR_OUT_OF_MEMORY);
    2178                 : 
    2179               0 :   return NS_OK;
    2180                 : }
    2181                 : 
    2182                 : void
    2183               0 : nsFormControlList::DropFormReference()
    2184                 : {
    2185               0 :   mForm = nsnull;
    2186               0 :   Clear();
    2187               0 : }
    2188                 : 
    2189                 : void
    2190               0 : nsFormControlList::Clear()
    2191                 : {
    2192                 :   // Null out childrens' pointer to me.  No refcounting here
    2193               0 :   for (PRInt32 i = mElements.Length() - 1; i >= 0; i--) {
    2194               0 :     mElements[i]->ClearForm(false);
    2195                 :   }
    2196               0 :   mElements.Clear();
    2197                 : 
    2198               0 :   for (PRInt32 i = mNotInElements.Length() - 1; i >= 0; i--) {
    2199               0 :     mNotInElements[i]->ClearForm(false);
    2200                 :   }
    2201               0 :   mNotInElements.Clear();
    2202                 : 
    2203               0 :   mNameLookupTable.Clear();
    2204               0 : }
    2205                 : 
    2206                 : void
    2207               0 : nsFormControlList::FlushPendingNotifications()
    2208                 : {
    2209               0 :   if (mForm) {
    2210               0 :     nsIDocument* doc = mForm->GetCurrentDoc();
    2211               0 :     if (doc) {
    2212               0 :       doc->FlushPendingNotifications(Flush_Content);
    2213                 :     }
    2214                 :   }
    2215               0 : }
    2216                 : 
    2217                 : static PLDHashOperator
    2218               0 : ControlTraverser(const nsAString& key, nsISupports* control, void* userArg)
    2219                 : {
    2220                 :   nsCycleCollectionTraversalCallback *cb = 
    2221               0 :     static_cast<nsCycleCollectionTraversalCallback*>(userArg);
    2222                 :  
    2223               0 :   cb->NoteXPCOMChild(control);
    2224               0 :   return PL_DHASH_NEXT;
    2225                 : }
    2226                 : 
    2227            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsFormControlList)
    2228               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFormControlList)
    2229               0 :   tmp->Clear();
    2230               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
    2231               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    2232               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFormControlList)
    2233               0 :   tmp->mNameLookupTable.EnumerateRead(ControlTraverser, &cb);
    2234               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
    2235               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    2236               0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsFormControlList)
    2237               0 :   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
    2238               0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
    2239                 : 
    2240                 : DOMCI_DATA(HTMLCollection, nsFormControlList)
    2241                 : 
    2242                 : // XPConnect interface list for nsFormControlList
    2243               0 : NS_INTERFACE_TABLE_HEAD(nsFormControlList)
    2244               0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    2245               0 :   NS_INTERFACE_TABLE2(nsFormControlList,
    2246                 :                       nsIHTMLCollection,
    2247                 :                       nsIDOMHTMLCollection)
    2248               0 :   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsFormControlList)
    2249               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(HTMLCollection)
    2250               0 : NS_INTERFACE_MAP_END
    2251                 : 
    2252                 : 
    2253               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFormControlList)
    2254               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFormControlList)
    2255                 : 
    2256                 : 
    2257                 : // nsIDOMHTMLCollection interface
    2258                 : 
    2259                 : NS_IMETHODIMP    
    2260               0 : nsFormControlList::GetLength(PRUint32* aLength)
    2261                 : {
    2262               0 :   FlushPendingNotifications();
    2263               0 :   *aLength = mElements.Length();
    2264               0 :   return NS_OK;
    2265                 : }
    2266                 : 
    2267                 : NS_IMETHODIMP
    2268               0 : nsFormControlList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
    2269                 : {
    2270               0 :   nsISupports* item = GetNodeAt(aIndex);
    2271               0 :   if (!item) {
    2272               0 :     *aReturn = nsnull;
    2273                 : 
    2274               0 :     return NS_OK;
    2275                 :   }
    2276                 : 
    2277               0 :   return CallQueryInterface(item, aReturn);
    2278                 : }
    2279                 : 
    2280                 : NS_IMETHODIMP 
    2281               0 : nsFormControlList::NamedItem(const nsAString& aName,
    2282                 :                              nsIDOMNode** aReturn)
    2283                 : {
    2284               0 :   FlushPendingNotifications();
    2285                 : 
    2286               0 :   *aReturn = nsnull;
    2287                 : 
    2288               0 :   nsCOMPtr<nsISupports> supports;
    2289                 :   
    2290               0 :   if (!mNameLookupTable.Get(aName, getter_AddRefs(supports))) {
    2291                 :     // key not found
    2292               0 :     return NS_OK;
    2293                 :   }
    2294                 : 
    2295               0 :   if (!supports) {
    2296               0 :     return NS_OK;
    2297                 :   }
    2298                 : 
    2299                 :   // We found something, check if it's a node
    2300               0 :   CallQueryInterface(supports, aReturn);
    2301               0 :   if (*aReturn) {
    2302               0 :     return NS_OK;
    2303                 :   }
    2304                 : 
    2305                 :   // If not, we check if it's a node list.
    2306               0 :   nsCOMPtr<nsIDOMNodeList> nodeList = do_QueryInterface(supports);
    2307               0 :   NS_ASSERTION(nodeList, "Huh, what's going one here?");
    2308               0 :   if (!nodeList) {
    2309               0 :     return NS_OK;
    2310                 :   }
    2311                 : 
    2312                 :   // And since we're only asking for one node here, we return the first
    2313                 :   // one from the list.
    2314               0 :   return nodeList->Item(0, aReturn);
    2315                 : }
    2316                 : 
    2317                 : nsISupports*
    2318               0 : nsFormControlList::NamedItemInternal(const nsAString& aName,
    2319                 :                                      bool aFlushContent)
    2320                 : {
    2321               0 :   if (aFlushContent) {
    2322               0 :     FlushPendingNotifications();
    2323                 :   }
    2324                 : 
    2325               0 :   return mNameLookupTable.GetWeak(aName);
    2326                 : }
    2327                 : 
    2328                 : nsresult
    2329               0 : nsFormControlList::AddElementToTable(nsGenericHTMLFormElement* aChild,
    2330                 :                                      const nsAString& aName)
    2331                 : {
    2332               0 :   if (!ShouldBeInElements(aChild)) {
    2333               0 :     return NS_OK;
    2334                 :   }
    2335                 : 
    2336               0 :   nsCOMPtr<nsISupports> supports;
    2337               0 :   mNameLookupTable.Get(aName, getter_AddRefs(supports));
    2338                 : 
    2339               0 :   if (!supports) {
    2340                 :     // No entry found, add the form control
    2341               0 :     NS_ENSURE_TRUE(mNameLookupTable.Put(aName,
    2342                 :                                         NS_ISUPPORTS_CAST(nsIContent*, aChild)),
    2343                 :                    NS_ERROR_FAILURE);
    2344                 :   } else {
    2345                 :     // Found something in the hash, check its type
    2346               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(supports);
    2347                 : 
    2348               0 :     if (content) {
    2349                 :       // Check if the new content is the same as the one we found in the
    2350                 :       // hash, if it is then we leave it in the hash as it is, this will
    2351                 :       // happen if a form control has both a name and an id with the same
    2352                 :       // value
    2353               0 :       if (content == aChild) {
    2354               0 :         return NS_OK;
    2355                 :       }
    2356                 : 
    2357                 :       // Found an element, create a list, add the element to the list and put
    2358                 :       // the list in the hash
    2359               0 :       nsSimpleContentList *list = new nsSimpleContentList(mForm);
    2360                 : 
    2361               0 :       NS_ASSERTION(content->GetParent(), "Item in list without parent");
    2362                 : 
    2363                 :       // Determine the ordering between the new and old element.
    2364               0 :       bool newFirst = nsContentUtils::PositionIsBefore(aChild, content);
    2365                 : 
    2366               0 :       list->AppendElement(newFirst ? aChild : content);
    2367               0 :       list->AppendElement(newFirst ? content : aChild);
    2368                 : 
    2369                 : 
    2370               0 :       nsCOMPtr<nsISupports> listSupports = do_QueryObject(list);
    2371                 : 
    2372                 :       // Replace the element with the list.
    2373               0 :       NS_ENSURE_TRUE(mNameLookupTable.Put(aName, listSupports),
    2374                 :                      NS_ERROR_FAILURE);
    2375                 :     } else {
    2376                 :       // There's already a list in the hash, add the child to the list
    2377               0 :       nsCOMPtr<nsIDOMNodeList> nodeList = do_QueryInterface(supports);
    2378               0 :       NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
    2379                 : 
    2380                 :       // Upcast, uggly, but it works!
    2381                 :       nsSimpleContentList *list =
    2382               0 :         static_cast<nsSimpleContentList*>(nodeList.get());
    2383                 : 
    2384               0 :       NS_ASSERTION(list->Length() > 1,
    2385                 :                    "List should have been converted back to a single element");
    2386                 : 
    2387                 :       // Fast-path appends; this check is ok even if the child is
    2388                 :       // already in the list, since if it tests true the child would
    2389                 :       // have come at the end of the list, and the PositionIsBefore
    2390                 :       // will test false.
    2391               0 :       if (nsContentUtils::PositionIsBefore(list->GetNodeAt(list->Length() - 1), aChild)) {
    2392               0 :         list->AppendElement(aChild);
    2393               0 :         return NS_OK;
    2394                 :       }
    2395                 : 
    2396                 :       // If a control has a name equal to its id, it could be in the
    2397                 :       // list already.
    2398               0 :       if (list->IndexOf(aChild) != -1) {
    2399               0 :         return NS_OK;
    2400                 :       }
    2401                 :       
    2402                 :       // first is the first possible insertion index, last is the last possible
    2403                 :       // insertion index
    2404               0 :       PRUint32 first = 0;
    2405               0 :       PRUint32 last = list->Length() - 1;
    2406                 :       PRUint32 mid;
    2407                 :       
    2408                 :       // Stop when there is only one index in our range
    2409               0 :       while (last != first) {
    2410               0 :         mid = (first + last) / 2;
    2411                 :           
    2412               0 :         if (nsContentUtils::PositionIsBefore(aChild, list->GetNodeAt(mid)))
    2413               0 :           last = mid;
    2414                 :         else
    2415               0 :           first = mid + 1;
    2416                 :       }
    2417                 : 
    2418               0 :       list->InsertElementAt(aChild, first);
    2419                 :     }
    2420                 :   }
    2421                 : 
    2422               0 :   return NS_OK;
    2423                 : }
    2424                 : 
    2425                 : nsresult
    2426               0 : nsFormControlList::IndexOfControl(nsIFormControl* aControl,
    2427                 :                                   PRInt32* aIndex)
    2428                 : {
    2429                 :   // Note -- not a DOM method; callers should handle flushing themselves
    2430                 :   
    2431               0 :   NS_ENSURE_ARG_POINTER(aIndex);
    2432                 : 
    2433               0 :   *aIndex = mElements.IndexOf(aControl);
    2434                 : 
    2435               0 :   return NS_OK;
    2436                 : }
    2437                 : 
    2438                 : nsresult
    2439               0 : nsFormControlList::RemoveElementFromTable(nsGenericHTMLFormElement* aChild,
    2440                 :                                           const nsAString& aName)
    2441                 : {
    2442               0 :   if (!ShouldBeInElements(aChild)) {
    2443               0 :     return NS_OK;
    2444                 :   }
    2445                 : 
    2446               0 :   nsCOMPtr<nsISupports> supports;
    2447                 : 
    2448               0 :   if (!mNameLookupTable.Get(aName, getter_AddRefs(supports)))
    2449               0 :     return NS_OK;
    2450                 : 
    2451               0 :   nsCOMPtr<nsIFormControl> fctrl(do_QueryInterface(supports));
    2452                 : 
    2453               0 :   if (fctrl) {
    2454                 :     // Single element in the hash, just remove it if it's the one
    2455                 :     // we're trying to remove...
    2456               0 :     if (fctrl == aChild) {
    2457               0 :       mNameLookupTable.Remove(aName);
    2458                 :     }
    2459                 : 
    2460               0 :     return NS_OK;
    2461                 :   }
    2462                 : 
    2463               0 :   nsCOMPtr<nsIDOMNodeList> nodeList(do_QueryInterface(supports));
    2464               0 :   NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
    2465                 : 
    2466                 :   // Upcast, uggly, but it works!
    2467               0 :   nsBaseContentList *list = static_cast<nsBaseContentList*>(nodeList.get());
    2468                 : 
    2469               0 :   list->RemoveElement(aChild);
    2470                 : 
    2471               0 :   PRUint32 length = 0;
    2472               0 :   list->GetLength(&length);
    2473                 : 
    2474               0 :   if (!length) {
    2475                 :     // If the list is empty we remove if from our hash, this shouldn't
    2476                 :     // happen tho
    2477               0 :     mNameLookupTable.Remove(aName);
    2478               0 :   } else if (length == 1) {
    2479                 :     // Only one element left, replace the list in the hash with the
    2480                 :     // single element.
    2481               0 :     nsIContent* node = list->GetNodeAt(0);
    2482               0 :     if (node) {
    2483               0 :       NS_ENSURE_TRUE(mNameLookupTable.Put(aName, node),NS_ERROR_FAILURE);
    2484                 :     }
    2485                 :   }
    2486                 : 
    2487               0 :   return NS_OK;
    2488                 : }
    2489                 : 
    2490                 : nsresult
    2491               0 : nsFormControlList::GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aControls) const
    2492                 : {
    2493                 : #ifdef DEBUG
    2494               0 :   AssertDocumentOrder(mElements, mForm);
    2495               0 :   AssertDocumentOrder(mNotInElements, mForm);
    2496                 : #endif
    2497                 : 
    2498               0 :   aControls.Clear();
    2499                 : 
    2500                 :   // Merge the elements list and the not in elements list. Both lists are
    2501                 :   // already sorted.
    2502               0 :   PRUint32 elementsLen = mElements.Length();
    2503               0 :   PRUint32 notInElementsLen = mNotInElements.Length();
    2504               0 :   aControls.SetCapacity(elementsLen + notInElementsLen);
    2505                 : 
    2506               0 :   PRUint32 elementsIdx = 0;
    2507               0 :   PRUint32 notInElementsIdx = 0;
    2508                 : 
    2509               0 :   while (elementsIdx < elementsLen || notInElementsIdx < notInElementsLen) {
    2510                 :     // Check whether we're done with mElements
    2511               0 :     if (elementsIdx == elementsLen) {
    2512               0 :       NS_ASSERTION(notInElementsIdx < notInElementsLen,
    2513                 :                    "Should have remaining not-in-elements");
    2514                 :       // Append the remaining mNotInElements elements
    2515               0 :       if (!aControls.AppendElements(mNotInElements.Elements() +
    2516                 :                                       notInElementsIdx,
    2517                 :                                     notInElementsLen -
    2518               0 :                                       notInElementsIdx)) {
    2519               0 :         return NS_ERROR_OUT_OF_MEMORY;
    2520                 :       }
    2521               0 :       break;
    2522                 :     }
    2523                 :     // Check whether we're done with mNotInElements
    2524               0 :     if (notInElementsIdx == notInElementsLen) {
    2525               0 :       NS_ASSERTION(elementsIdx < elementsLen,
    2526                 :                    "Should have remaining in-elements");
    2527                 :       // Append the remaining mElements elements
    2528               0 :       if (!aControls.AppendElements(mElements.Elements() +
    2529                 :                                       elementsIdx,
    2530                 :                                     elementsLen -
    2531               0 :                                       elementsIdx)) {
    2532               0 :         return NS_ERROR_OUT_OF_MEMORY;
    2533                 :       }
    2534               0 :       break;
    2535                 :     }
    2536                 :     // Both lists have elements left.
    2537               0 :     NS_ASSERTION(mElements[elementsIdx] &&
    2538                 :                  mNotInElements[notInElementsIdx],
    2539                 :                  "Should have remaining elements");
    2540                 :     // Determine which of the two elements should be ordered
    2541                 :     // first and add it to the end of the list.
    2542                 :     nsGenericHTMLFormElement* elementToAdd;
    2543               0 :     if (CompareFormControlPosition(mElements[elementsIdx],
    2544               0 :                                    mNotInElements[notInElementsIdx],
    2545               0 :                                    mForm) < 0) {
    2546               0 :       elementToAdd = mElements[elementsIdx];
    2547               0 :       ++elementsIdx;
    2548                 :     } else {
    2549               0 :       elementToAdd = mNotInElements[notInElementsIdx];
    2550               0 :       ++notInElementsIdx;
    2551                 :     }
    2552                 :     // Add the first element to the list.
    2553               0 :     if (!aControls.AppendElement(elementToAdd)) {
    2554               0 :       return NS_ERROR_OUT_OF_MEMORY;
    2555                 :     }
    2556                 :   }
    2557                 : 
    2558               0 :   NS_ASSERTION(aControls.Length() == elementsLen + notInElementsLen,
    2559                 :                "Not all form controls were added to the sorted list");
    2560                 : #ifdef DEBUG
    2561               0 :   AssertDocumentOrder(aControls, mForm);
    2562                 : #endif
    2563                 : 
    2564               0 :   return NS_OK;
    2565                 : }
    2566                 : 
    2567                 : nsIContent*
    2568               0 : nsFormControlList::GetNodeAt(PRUint32 aIndex)
    2569                 : {
    2570               0 :   FlushPendingNotifications();
    2571                 : 
    2572               0 :   return mElements.SafeElementAt(aIndex, nsnull);
    2573                 : }
    2574                 : 
    2575                 : nsISupports*
    2576               0 : nsFormControlList::GetNamedItem(const nsAString& aName, nsWrapperCache **aCache)
    2577                 : {
    2578               0 :   nsISupports *item = NamedItemInternal(aName, true);
    2579               0 :   *aCache = nsnull;
    2580               0 :   return item;
    2581            4392 : }

Generated by: LCOV version 1.7