LCOV - code coverage report
Current view: top level - dom/html - HTMLFormControlsCollection.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 163 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 28 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/dom/HTMLFormControlsCollection.h"
       8             : 
       9             : #include "mozilla/FlushType.h"
      10             : #include "mozilla/dom/BindingUtils.h"
      11             : #include "mozilla/dom/Element.h"
      12             : #include "mozilla/dom/HTMLFormControlsCollectionBinding.h"
      13             : #include "mozilla/dom/HTMLFormElement.h"
      14             : #include "nsGenericHTMLElement.h" // nsGenericHTMLFormElement
      15             : #include "nsIDocument.h"
      16             : #include "nsIDOMNode.h"
      17             : #include "nsIDOMNodeList.h"
      18             : #include "nsIFormControl.h"
      19             : #include "RadioNodeList.h"
      20             : #include "jsfriendapi.h"
      21             : 
      22             : namespace mozilla {
      23             : namespace dom {
      24             : 
      25             : /* static */ bool
      26           0 : HTMLFormControlsCollection::ShouldBeInElements(nsIFormControl* aFormControl)
      27             : {
      28             :   // For backwards compatibility (with 4.x and IE) we must not add
      29             :   // <input type=image> elements to the list of form controls in a
      30             :   // form.
      31             : 
      32           0 :   switch (aFormControl->ControlType()) {
      33             :   case NS_FORM_BUTTON_BUTTON :
      34             :   case NS_FORM_BUTTON_RESET :
      35             :   case NS_FORM_BUTTON_SUBMIT :
      36             :   case NS_FORM_INPUT_BUTTON :
      37             :   case NS_FORM_INPUT_CHECKBOX :
      38             :   case NS_FORM_INPUT_COLOR :
      39             :   case NS_FORM_INPUT_EMAIL :
      40             :   case NS_FORM_INPUT_FILE :
      41             :   case NS_FORM_INPUT_HIDDEN :
      42             :   case NS_FORM_INPUT_RESET :
      43             :   case NS_FORM_INPUT_PASSWORD :
      44             :   case NS_FORM_INPUT_RADIO :
      45             :   case NS_FORM_INPUT_SEARCH :
      46             :   case NS_FORM_INPUT_SUBMIT :
      47             :   case NS_FORM_INPUT_TEXT :
      48             :   case NS_FORM_INPUT_TEL :
      49             :   case NS_FORM_INPUT_URL :
      50             :   case NS_FORM_INPUT_NUMBER :
      51             :   case NS_FORM_INPUT_RANGE :
      52             :   case NS_FORM_INPUT_DATE :
      53             :   case NS_FORM_INPUT_TIME :
      54             :   case NS_FORM_INPUT_MONTH :
      55             :   case NS_FORM_INPUT_WEEK :
      56             :   case NS_FORM_INPUT_DATETIME_LOCAL :
      57             :   case NS_FORM_SELECT :
      58             :   case NS_FORM_TEXTAREA :
      59             :   case NS_FORM_FIELDSET :
      60             :   case NS_FORM_OBJECT :
      61             :   case NS_FORM_OUTPUT :
      62           0 :     return true;
      63             :   }
      64             : 
      65             :   // These form control types are not supposed to end up in the
      66             :   // form.elements array
      67             :   //
      68             :   // NS_FORM_INPUT_IMAGE
      69             :   //
      70             :   // XXXbz maybe we should just check for that type here instead of the big
      71             :   // switch?
      72             : 
      73           0 :   return false;
      74             : }
      75             : 
      76           0 : HTMLFormControlsCollection::HTMLFormControlsCollection(HTMLFormElement* aForm)
      77             :   : mForm(aForm)
      78             :   // Initialize the elements list to have an initial capacity
      79             :   // of 8 to reduce allocations on small forms.
      80             :   , mElements(8)
      81           0 :   , mNameLookupTable(HTMLFormElement::FORM_CONTROL_LIST_HASHTABLE_LENGTH)
      82             : {
      83           0 : }
      84             : 
      85           0 : HTMLFormControlsCollection::~HTMLFormControlsCollection()
      86             : {
      87           0 :   mForm = nullptr;
      88           0 :   Clear();
      89           0 : }
      90             : 
      91             : void
      92           0 : HTMLFormControlsCollection::DropFormReference()
      93             : {
      94           0 :   mForm = nullptr;
      95           0 :   Clear();
      96           0 : }
      97             : 
      98             : void
      99           0 : HTMLFormControlsCollection::Clear()
     100             : {
     101             :   // Null out childrens' pointer to me.  No refcounting here
     102           0 :   for (int32_t i = mElements.Length() - 1; i >= 0; i--) {
     103           0 :     mElements[i]->ClearForm(false, false);
     104             :   }
     105           0 :   mElements.Clear();
     106             : 
     107           0 :   for (int32_t i = mNotInElements.Length() - 1; i >= 0; i--) {
     108           0 :     mNotInElements[i]->ClearForm(false, false);
     109             :   }
     110           0 :   mNotInElements.Clear();
     111             : 
     112           0 :   mNameLookupTable.Clear();
     113           0 : }
     114             : 
     115             : void
     116           0 : HTMLFormControlsCollection::FlushPendingNotifications()
     117             : {
     118           0 :   if (mForm) {
     119           0 :     nsIDocument* doc = mForm->GetUncomposedDoc();
     120           0 :     if (doc) {
     121           0 :       doc->FlushPendingNotifications(FlushType::Content);
     122             :     }
     123             :   }
     124           0 : }
     125             : 
     126             : NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLFormControlsCollection)
     127             : 
     128           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(HTMLFormControlsCollection)
     129             :   // Note: We intentionally don't set tmp->mForm to nullptr here, since doing
     130             :   // so may result in crashes because of inconsistent null-checking after the
     131             :   // object gets unlinked.
     132           0 :   tmp->Clear();
     133           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
     134           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     135           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(HTMLFormControlsCollection)
     136           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNameLookupTable)
     137           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     138           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(HTMLFormControlsCollection)
     139           0 :   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
     140           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
     141             : 
     142             : // XPConnect interface list for HTMLFormControlsCollection
     143           0 : NS_INTERFACE_TABLE_HEAD(HTMLFormControlsCollection)
     144           0 :   NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
     145           0 :   NS_INTERFACE_TABLE(HTMLFormControlsCollection,
     146             :                      nsIHTMLCollection,
     147             :                      nsIDOMHTMLCollection)
     148           0 :   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(HTMLFormControlsCollection)
     149           0 : NS_INTERFACE_MAP_END
     150             : 
     151             : 
     152           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(HTMLFormControlsCollection)
     153           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(HTMLFormControlsCollection)
     154             : 
     155             : 
     156             : // nsIDOMHTMLCollection interface
     157             : 
     158             : NS_IMETHODIMP
     159           0 : HTMLFormControlsCollection::GetLength(uint32_t* aLength)
     160             : {
     161           0 :   FlushPendingNotifications();
     162           0 :   *aLength = mElements.Length();
     163           0 :   return NS_OK;
     164             : }
     165             : 
     166             : NS_IMETHODIMP
     167           0 : HTMLFormControlsCollection::Item(uint32_t aIndex, nsIDOMNode** aReturn)
     168             : {
     169           0 :   nsISupports* item = GetElementAt(aIndex);
     170           0 :   if (!item) {
     171           0 :     *aReturn = nullptr;
     172             : 
     173           0 :     return NS_OK;
     174             :   }
     175             : 
     176           0 :   return CallQueryInterface(item, aReturn);
     177             : }
     178             : 
     179             : NS_IMETHODIMP
     180           0 : HTMLFormControlsCollection::NamedItem(const nsAString& aName,
     181             :                                       nsIDOMNode** aReturn)
     182             : {
     183           0 :   FlushPendingNotifications();
     184             : 
     185           0 :   *aReturn = nullptr;
     186             : 
     187           0 :   nsCOMPtr<nsISupports> supports;
     188             : 
     189           0 :   if (!mNameLookupTable.Get(aName, getter_AddRefs(supports))) {
     190             :     // key not found
     191           0 :     return NS_OK;
     192             :   }
     193             : 
     194           0 :   if (!supports) {
     195           0 :     return NS_OK;
     196             :   }
     197             : 
     198             :   // We found something, check if it's a node
     199           0 :   CallQueryInterface(supports, aReturn);
     200           0 :   if (*aReturn) {
     201           0 :     return NS_OK;
     202             :   }
     203             : 
     204             :   // If not, we check if it's a node list.
     205           0 :   nsCOMPtr<nsIDOMNodeList> nodeList = do_QueryInterface(supports);
     206           0 :   NS_ASSERTION(nodeList, "Huh, what's going one here?");
     207           0 :   if (!nodeList) {
     208           0 :     return NS_OK;
     209             :   }
     210             : 
     211             :   // And since we're only asking for one node here, we return the first
     212             :   // one from the list.
     213           0 :   return nodeList->Item(0, aReturn);
     214             : }
     215             : 
     216             : nsISupports*
     217           0 : HTMLFormControlsCollection::NamedItemInternal(const nsAString& aName,
     218             :                                               bool aFlushContent)
     219             : {
     220           0 :   if (aFlushContent) {
     221           0 :     FlushPendingNotifications();
     222             :   }
     223             : 
     224           0 :   return mNameLookupTable.GetWeak(aName);
     225             : }
     226             : 
     227             : nsresult
     228           0 : HTMLFormControlsCollection::AddElementToTable(nsGenericHTMLFormElement* aChild,
     229             :                                               const nsAString& aName)
     230             : {
     231           0 :   if (!ShouldBeInElements(aChild)) {
     232           0 :     return NS_OK;
     233             :   }
     234             : 
     235           0 :   return mForm->AddElementToTableInternal(mNameLookupTable, aChild, aName);
     236             : }
     237             : 
     238             : nsresult
     239           0 : HTMLFormControlsCollection::IndexOfControl(nsIFormControl* aControl,
     240             :                                            int32_t* aIndex)
     241             : {
     242             :   // Note -- not a DOM method; callers should handle flushing themselves
     243             : 
     244           0 :   NS_ENSURE_ARG_POINTER(aIndex);
     245             : 
     246           0 :   *aIndex = mElements.IndexOf(aControl);
     247             : 
     248           0 :   return NS_OK;
     249             : }
     250             : 
     251             : nsresult
     252           0 : HTMLFormControlsCollection::RemoveElementFromTable(
     253             :   nsGenericHTMLFormElement* aChild, const nsAString& aName)
     254             : {
     255           0 :   if (!ShouldBeInElements(aChild)) {
     256           0 :     return NS_OK;
     257             :   }
     258             : 
     259           0 :   return mForm->RemoveElementFromTableInternal(mNameLookupTable, aChild, aName);
     260             : }
     261             : 
     262             : nsresult
     263           0 : HTMLFormControlsCollection::GetSortedControls(
     264             :   nsTArray<nsGenericHTMLFormElement*>& aControls) const
     265             : {
     266             : #ifdef DEBUG
     267           0 :   HTMLFormElement::AssertDocumentOrder(mElements, mForm);
     268           0 :   HTMLFormElement::AssertDocumentOrder(mNotInElements, mForm);
     269             : #endif
     270             : 
     271           0 :   aControls.Clear();
     272             : 
     273             :   // Merge the elements list and the not in elements list. Both lists are
     274             :   // already sorted.
     275           0 :   uint32_t elementsLen = mElements.Length();
     276           0 :   uint32_t notInElementsLen = mNotInElements.Length();
     277           0 :   aControls.SetCapacity(elementsLen + notInElementsLen);
     278             : 
     279           0 :   uint32_t elementsIdx = 0;
     280           0 :   uint32_t notInElementsIdx = 0;
     281             : 
     282           0 :   while (elementsIdx < elementsLen || notInElementsIdx < notInElementsLen) {
     283             :     // Check whether we're done with mElements
     284           0 :     if (elementsIdx == elementsLen) {
     285           0 :       NS_ASSERTION(notInElementsIdx < notInElementsLen,
     286             :                    "Should have remaining not-in-elements");
     287             :       // Append the remaining mNotInElements elements
     288           0 :       if (!aControls.AppendElements(mNotInElements.Elements() +
     289           0 :                                       notInElementsIdx,
     290           0 :                                     notInElementsLen -
     291             :                                       notInElementsIdx)) {
     292           0 :         return NS_ERROR_OUT_OF_MEMORY;
     293             :       }
     294           0 :       break;
     295             :     }
     296             :     // Check whether we're done with mNotInElements
     297           0 :     if (notInElementsIdx == notInElementsLen) {
     298           0 :       NS_ASSERTION(elementsIdx < elementsLen,
     299             :                    "Should have remaining in-elements");
     300             :       // Append the remaining mElements elements
     301           0 :       if (!aControls.AppendElements(mElements.Elements() +
     302           0 :                                       elementsIdx,
     303           0 :                                     elementsLen -
     304             :                                       elementsIdx)) {
     305           0 :         return NS_ERROR_OUT_OF_MEMORY;
     306             :       }
     307           0 :       break;
     308             :     }
     309             :     // Both lists have elements left.
     310           0 :     NS_ASSERTION(mElements[elementsIdx] &&
     311             :                  mNotInElements[notInElementsIdx],
     312             :                  "Should have remaining elements");
     313             :     // Determine which of the two elements should be ordered
     314             :     // first and add it to the end of the list.
     315             :     nsGenericHTMLFormElement* elementToAdd;
     316           0 :     if (HTMLFormElement::CompareFormControlPosition(
     317           0 :           mElements[elementsIdx], mNotInElements[notInElementsIdx], mForm) < 0) {
     318           0 :       elementToAdd = mElements[elementsIdx];
     319           0 :       ++elementsIdx;
     320             :     } else {
     321           0 :       elementToAdd = mNotInElements[notInElementsIdx];
     322           0 :       ++notInElementsIdx;
     323             :     }
     324             :     // Add the first element to the list.
     325           0 :     if (!aControls.AppendElement(elementToAdd)) {
     326           0 :       return NS_ERROR_OUT_OF_MEMORY;
     327             :     }
     328             :   }
     329             : 
     330           0 :   NS_ASSERTION(aControls.Length() == elementsLen + notInElementsLen,
     331             :                "Not all form controls were added to the sorted list");
     332             : #ifdef DEBUG
     333           0 :   HTMLFormElement::AssertDocumentOrder(aControls, mForm);
     334             : #endif
     335             : 
     336           0 :   return NS_OK;
     337             : }
     338             : 
     339             : Element*
     340           0 : HTMLFormControlsCollection::GetElementAt(uint32_t aIndex)
     341             : {
     342           0 :   FlushPendingNotifications();
     343             : 
     344           0 :   return mElements.SafeElementAt(aIndex, nullptr);
     345             : }
     346             : 
     347             : /* virtual */ nsINode*
     348           0 : HTMLFormControlsCollection::GetParentObject()
     349             : {
     350           0 :   return mForm;
     351             : }
     352             : 
     353             : /* virtual */ Element*
     354           0 : HTMLFormControlsCollection::GetFirstNamedElement(const nsAString& aName, bool& aFound)
     355             : {
     356           0 :   Nullable<OwningRadioNodeListOrElement> maybeResult;
     357           0 :   NamedGetter(aName, aFound, maybeResult);
     358           0 :   if (!aFound) {
     359           0 :     return nullptr;
     360             :   }
     361           0 :   MOZ_ASSERT(!maybeResult.IsNull());
     362           0 :   const OwningRadioNodeListOrElement& result = maybeResult.Value();
     363           0 :   if (result.IsElement()) {
     364           0 :     return result.GetAsElement().get();
     365             :   }
     366           0 :   if (result.IsRadioNodeList()) {
     367           0 :     RadioNodeList& nodelist = result.GetAsRadioNodeList();
     368           0 :     return nodelist.Item(0)->AsElement();
     369             :   }
     370           0 :   MOZ_ASSERT_UNREACHABLE("Should only have Elements and NodeLists here.");
     371             :   return nullptr;
     372             : }
     373             : 
     374             : void
     375           0 : HTMLFormControlsCollection::NamedGetter(const nsAString& aName,
     376             :                                         bool& aFound,
     377             :                                         Nullable<OwningRadioNodeListOrElement>& aResult)
     378             : {
     379           0 :   nsISupports* item = NamedItemInternal(aName, true);
     380           0 :   if (!item) {
     381           0 :     aFound = false;
     382           0 :     return;
     383             :   }
     384           0 :   aFound = true;
     385           0 :   if (nsCOMPtr<Element> element = do_QueryInterface(item)) {
     386           0 :     aResult.SetValue().SetAsElement() = element;
     387           0 :     return;
     388             :   }
     389           0 :   if (nsCOMPtr<RadioNodeList> nodelist = do_QueryInterface(item)) {
     390           0 :     aResult.SetValue().SetAsRadioNodeList() = nodelist;
     391           0 :     return;
     392             :   }
     393           0 :   MOZ_ASSERT_UNREACHABLE("Should only have Elements and NodeLists here.");
     394             : }
     395             : 
     396             : void
     397           0 : HTMLFormControlsCollection::GetSupportedNames(nsTArray<nsString>& aNames)
     398             : {
     399           0 :   FlushPendingNotifications();
     400             :   // Just enumerate mNameLookupTable.  This won't guarantee order, but
     401             :   // that's OK, because the HTML5 spec doesn't define an order for
     402             :   // this enumeration.
     403           0 :   for (auto iter = mNameLookupTable.Iter(); !iter.Done(); iter.Next()) {
     404           0 :     aNames.AppendElement(iter.Key());
     405             :   }
     406           0 : }
     407             : 
     408             : /* virtual */ JSObject*
     409           0 : HTMLFormControlsCollection::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     410             : {
     411           0 :   return HTMLFormControlsCollectionBinding::Wrap(aCx, this, aGivenProto);
     412             : }
     413             : 
     414             : } // namespace dom
     415             : } // namespace mozilla

Generated by: LCOV version 1.13