LCOV - code coverage report
Current view: top level - dom/base - nsContentList.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 214 442 48.4 %
Date: 2017-07-14 16:53:18 Functions: 40 75 53.3 %
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             : /*
       8             :  * nsBaseContentList is a basic list of content nodes; nsContentList
       9             :  * is a commonly used NodeList implementation (used for
      10             :  * getElementsByTagName, some properties on nsIDOMHTMLDocument, etc).
      11             :  */
      12             : 
      13             : #include "nsContentList.h"
      14             : #include "nsIContent.h"
      15             : #include "nsIDOMNode.h"
      16             : #include "nsIDocument.h"
      17             : #include "mozilla/dom/Element.h"
      18             : #include "nsWrapperCacheInlines.h"
      19             : #include "nsContentUtils.h"
      20             : #include "nsCCUncollectableMarker.h"
      21             : #include "nsGkAtoms.h"
      22             : #include "mozilla/dom/HTMLCollectionBinding.h"
      23             : #include "mozilla/dom/NodeListBinding.h"
      24             : #include "mozilla/Likely.h"
      25             : #include "nsGenericHTMLElement.h"
      26             : #include "jsfriendapi.h"
      27             : #include <algorithm>
      28             : #include "mozilla/dom/NodeInfoInlines.h"
      29             : 
      30             : // Form related includes
      31             : #include "nsIDOMHTMLFormElement.h"
      32             : 
      33             : #include "PLDHashTable.h"
      34             : 
      35             : #ifdef DEBUG_CONTENT_LIST
      36             : #include "nsIContentIterator.h"
      37             : #define ASSERT_IN_SYNC AssertInSync()
      38             : #else
      39             : #define ASSERT_IN_SYNC PR_BEGIN_MACRO PR_END_MACRO
      40             : #endif
      41             : 
      42             : using namespace mozilla;
      43             : using namespace mozilla::dom;
      44             : 
      45           1 : nsBaseContentList::~nsBaseContentList()
      46             : {
      47           1 : }
      48             : 
      49             : NS_IMPL_CYCLE_COLLECTION_CLASS(nsBaseContentList)
      50           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsBaseContentList)
      51           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mElements)
      52           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
      53           0 :   tmp->RemoveFromCaches();
      54           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      55           8 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBaseContentList)
      56           8 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElements)
      57           8 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      58          17 : NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsBaseContentList)
      59             : 
      60           0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsBaseContentList)
      61           0 :   if (nsCCUncollectableMarker::sGeneration && tmp->HasKnownLiveWrapper()) {
      62           0 :     for (uint32_t i = 0; i < tmp->mElements.Length(); ++i) {
      63           0 :       nsIContent* c = tmp->mElements[i];
      64           0 :       if (c->IsPurple()) {
      65           0 :         c->RemovePurple();
      66             :       }
      67           0 :       Element::MarkNodeChildren(c);
      68             :     }
      69           0 :     return true;
      70             :   }
      71           0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
      72             : 
      73           0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsBaseContentList)
      74           0 :   return nsCCUncollectableMarker::sGeneration && tmp->HasKnownLiveWrapper();
      75             : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
      76             : 
      77           0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsBaseContentList)
      78           0 :   return nsCCUncollectableMarker::sGeneration && tmp->HasKnownLiveWrapper();
      79             : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
      80             : 
      81             : #define NS_CONTENT_LIST_INTERFACES(_class)                                    \
      82             :     NS_INTERFACE_TABLE_ENTRY(_class, nsINodeList)                             \
      83             :     NS_INTERFACE_TABLE_ENTRY(_class, nsIDOMNodeList)
      84             : 
      85             : // QueryInterface implementation for nsBaseContentList
      86          70 : NS_INTERFACE_TABLE_HEAD(nsBaseContentList)
      87          70 :   NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
      88          62 :   NS_INTERFACE_TABLE(nsBaseContentList, nsINodeList, nsIDOMNodeList)
      89          62 :   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsBaseContentList)
      90           0 : NS_INTERFACE_MAP_END
      91             : 
      92             : 
      93          31 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsBaseContentList)
      94          12 : NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsBaseContentList,
      95             :                                                    LastRelease())
      96             : 
      97             : 
      98             : NS_IMETHODIMP
      99          14 : nsBaseContentList::GetLength(uint32_t* aLength)
     100             : {
     101          14 :   *aLength = mElements.Length();
     102             : 
     103          14 :   return NS_OK;
     104             : }
     105             : 
     106             : NS_IMETHODIMP
     107           0 : nsBaseContentList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
     108             : {
     109           0 :   nsISupports *tmp = Item(aIndex);
     110             : 
     111           0 :   if (!tmp) {
     112           0 :     *aReturn = nullptr;
     113             : 
     114           0 :     return NS_OK;
     115             :   }
     116             : 
     117           0 :   return CallQueryInterface(tmp, aReturn);
     118             : }
     119             : 
     120             : nsIContent*
     121           8 : nsBaseContentList::Item(uint32_t aIndex)
     122             : {
     123           8 :   return mElements.SafeElementAt(aIndex);
     124             : }
     125             : 
     126             : 
     127             : int32_t
     128           0 : nsBaseContentList::IndexOf(nsIContent *aContent, bool aDoFlush)
     129             : {
     130           0 :   return mElements.IndexOf(aContent);
     131             : }
     132             : 
     133             : int32_t
     134           0 : nsBaseContentList::IndexOf(nsIContent* aContent)
     135             : {
     136           0 :   return IndexOf(aContent, true);
     137             : }
     138             : 
     139           6 : NS_IMPL_CYCLE_COLLECTION_INHERITED(nsSimpleContentList, nsBaseContentList,
     140             :                                    mRoot)
     141             : 
     142          72 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsSimpleContentList)
     143          36 : NS_INTERFACE_MAP_END_INHERITING(nsBaseContentList)
     144             : 
     145             : 
     146          12 : NS_IMPL_ADDREF_INHERITED(nsSimpleContentList, nsBaseContentList)
     147           6 : NS_IMPL_RELEASE_INHERITED(nsSimpleContentList, nsBaseContentList)
     148             : 
     149             : JSObject*
     150           6 : nsSimpleContentList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
     151             : {
     152           6 :   return NodeListBinding::Wrap(cx, this, aGivenProto);
     153             : }
     154             : 
     155             : // Hashtable for storing nsContentLists
     156             : static PLDHashTable* gContentListHashTable;
     157             : 
     158             : #define RECENTLY_USED_CONTENT_LIST_CACHE_SIZE 31
     159             : static nsContentList*
     160             :   sRecentlyUsedContentLists[RECENTLY_USED_CONTENT_LIST_CACHE_SIZE] = {};
     161             : 
     162             : static MOZ_ALWAYS_INLINE uint32_t
     163           5 : RecentlyUsedCacheIndex(const nsContentListKey& aKey)
     164             : {
     165           5 :   return aKey.GetHash() % RECENTLY_USED_CONTENT_LIST_CACHE_SIZE;
     166             : }
     167             : 
     168             : struct ContentListHashEntry : public PLDHashEntryHdr
     169             : {
     170             :   nsContentList* mContentList;
     171             : };
     172             : 
     173             : static PLDHashNumber
     174           5 : ContentListHashtableHashKey(const void *key)
     175             : {
     176           5 :   const nsContentListKey* list = static_cast<const nsContentListKey *>(key);
     177           5 :   return list->GetHash();
     178             : }
     179             : 
     180             : static bool
     181           1 : ContentListHashtableMatchEntry(const PLDHashEntryHdr *entry, const void *key)
     182             : {
     183             :   const ContentListHashEntry *e =
     184           1 :     static_cast<const ContentListHashEntry *>(entry);
     185           1 :   const nsContentList* list = e->mContentList;
     186           1 :   const nsContentListKey* ourKey = static_cast<const nsContentListKey *>(key);
     187             : 
     188           1 :   return list->MatchesKey(*ourKey);
     189             : }
     190             : 
     191             : already_AddRefed<nsContentList>
     192           3 : NS_GetContentList(nsINode* aRootNode,
     193             :                   int32_t  aMatchNameSpaceId,
     194             :                   const nsAString& aTagname)
     195             : {
     196           3 :   NS_ASSERTION(aRootNode, "content list has to have a root");
     197             : 
     198           6 :   RefPtr<nsContentList> list;
     199             :   nsContentListKey hashKey(aRootNode, aMatchNameSpaceId, aTagname,
     200           3 :                            aRootNode->OwnerDoc()->IsHTMLDocument());
     201           3 :   uint32_t recentlyUsedCacheIndex = RecentlyUsedCacheIndex(hashKey);
     202           3 :   nsContentList* cachedList = sRecentlyUsedContentLists[recentlyUsedCacheIndex];
     203           3 :   if (cachedList && cachedList->MatchesKey(hashKey)) {
     204           0 :     list = cachedList;
     205           0 :     return list.forget();
     206             :   }
     207             : 
     208             :   static const PLDHashTableOps hash_table_ops =
     209             :   {
     210             :     ContentListHashtableHashKey,
     211             :     ContentListHashtableMatchEntry,
     212             :     PLDHashTable::MoveEntryStub,
     213             :     PLDHashTable::ClearEntryStub
     214             :   };
     215             : 
     216             :   // Initialize the hashtable if needed.
     217           3 :   if (!gContentListHashTable) {
     218           2 :     gContentListHashTable =
     219           2 :       new PLDHashTable(&hash_table_ops, sizeof(ContentListHashEntry));
     220             :   }
     221             : 
     222             :   // First we look in our hashtable.  Then we create a content list if needed
     223             :   auto entry = static_cast<ContentListHashEntry*>
     224           3 :                           (gContentListHashTable->Add(&hashKey, fallible));
     225           3 :   if (entry)
     226           3 :     list = entry->mContentList;
     227             : 
     228           3 :   if (!list) {
     229             :     // We need to create a ContentList and add it to our new entry, if
     230             :     // we have an entry
     231           6 :     nsCOMPtr<nsIAtom> xmlAtom = NS_Atomize(aTagname);
     232           6 :     nsCOMPtr<nsIAtom> htmlAtom;
     233           3 :     if (aMatchNameSpaceId == kNameSpaceID_Unknown) {
     234           2 :       nsAutoString lowercaseName;
     235           1 :       nsContentUtils::ASCIIToLower(aTagname, lowercaseName);
     236           1 :       htmlAtom = NS_Atomize(lowercaseName);
     237             :     } else {
     238           2 :       htmlAtom = xmlAtom;
     239             :     }
     240           6 :     list = new nsContentList(aRootNode, aMatchNameSpaceId, htmlAtom, xmlAtom);
     241           3 :     if (entry) {
     242           3 :       entry->mContentList = list;
     243             :     }
     244             :   }
     245             : 
     246           3 :   sRecentlyUsedContentLists[recentlyUsedCacheIndex] = list;
     247           3 :   return list.forget();
     248             : }
     249             : 
     250             : #ifdef DEBUG
     251             : const nsCacheableFuncStringContentList::ContentListType
     252             :   nsCacheableFuncStringNodeList::sType = nsCacheableFuncStringContentList::eNodeList;
     253             : const nsCacheableFuncStringContentList::ContentListType
     254             :   nsCacheableFuncStringHTMLCollection::sType = nsCacheableFuncStringContentList::eHTMLCollection;
     255             : #endif
     256             : 
     257             : // Hashtable for storing nsCacheableFuncStringContentList
     258             : static PLDHashTable* gFuncStringContentListHashTable;
     259             : 
     260             : struct FuncStringContentListHashEntry : public PLDHashEntryHdr
     261             : {
     262             :   nsCacheableFuncStringContentList* mContentList;
     263             : };
     264             : 
     265             : static PLDHashNumber
     266           0 : FuncStringContentListHashtableHashKey(const void *key)
     267             : {
     268             :   const nsFuncStringCacheKey* funcStringKey =
     269           0 :     static_cast<const nsFuncStringCacheKey *>(key);
     270           0 :   return funcStringKey->GetHash();
     271             : }
     272             : 
     273             : static bool
     274           0 : FuncStringContentListHashtableMatchEntry(const PLDHashEntryHdr *entry,
     275             :                                          const void *key)
     276             : {
     277             :   const FuncStringContentListHashEntry *e =
     278           0 :     static_cast<const FuncStringContentListHashEntry *>(entry);
     279             :   const nsFuncStringCacheKey* ourKey =
     280           0 :     static_cast<const nsFuncStringCacheKey *>(key);
     281             : 
     282           0 :   return e->mContentList->Equals(ourKey);
     283             : }
     284             : 
     285             : template<class ListType>
     286             : already_AddRefed<nsContentList>
     287           0 : GetFuncStringContentList(nsINode* aRootNode,
     288             :                          nsContentListMatchFunc aFunc,
     289             :                          nsContentListDestroyFunc aDestroyFunc,
     290             :                          nsFuncStringContentListDataAllocator aDataAllocator,
     291             :                          const nsAString& aString)
     292             : {
     293           0 :   NS_ASSERTION(aRootNode, "content list has to have a root");
     294             : 
     295           0 :   RefPtr<nsCacheableFuncStringContentList> list;
     296             : 
     297             :   static const PLDHashTableOps hash_table_ops =
     298             :   {
     299             :     FuncStringContentListHashtableHashKey,
     300             :     FuncStringContentListHashtableMatchEntry,
     301             :     PLDHashTable::MoveEntryStub,
     302             :     PLDHashTable::ClearEntryStub
     303             :   };
     304             : 
     305             :   // Initialize the hashtable if needed.
     306           0 :   if (!gFuncStringContentListHashTable) {
     307           0 :     gFuncStringContentListHashTable =
     308           0 :       new PLDHashTable(&hash_table_ops, sizeof(FuncStringContentListHashEntry));
     309             :   }
     310             : 
     311           0 :   FuncStringContentListHashEntry *entry = nullptr;
     312             :   // First we look in our hashtable.  Then we create a content list if needed
     313           0 :   if (gFuncStringContentListHashTable) {
     314           0 :     nsFuncStringCacheKey hashKey(aRootNode, aFunc, aString);
     315             : 
     316           0 :     entry = static_cast<FuncStringContentListHashEntry*>
     317           0 :       (gFuncStringContentListHashTable->Add(&hashKey, fallible));
     318           0 :     if (entry) {
     319           0 :       list = entry->mContentList;
     320             : #ifdef DEBUG
     321           0 :       MOZ_ASSERT_IF(list, list->mType == ListType::sType);
     322             : #endif
     323             :     }
     324             :   }
     325             : 
     326           0 :   if (!list) {
     327             :     // We need to create a ContentList and add it to our new entry, if
     328             :     // we have an entry
     329           0 :     list = new ListType(aRootNode, aFunc, aDestroyFunc, aDataAllocator,
     330             :                         aString);
     331           0 :     if (entry) {
     332           0 :       entry->mContentList = list;
     333             :     }
     334             :   }
     335             : 
     336             :   // Don't cache these lists globally
     337             : 
     338           0 :   return list.forget();
     339             : }
     340             : 
     341             : already_AddRefed<nsContentList>
     342           0 : NS_GetFuncStringNodeList(nsINode* aRootNode,
     343             :                          nsContentListMatchFunc aFunc,
     344             :                          nsContentListDestroyFunc aDestroyFunc,
     345             :                          nsFuncStringContentListDataAllocator aDataAllocator,
     346             :                          const nsAString& aString)
     347             : {
     348             :   return GetFuncStringContentList<nsCacheableFuncStringNodeList>(aRootNode,
     349             :                                                                  aFunc,
     350             :                                                                  aDestroyFunc,
     351             :                                                                  aDataAllocator,
     352           0 :                                                                  aString);
     353             : }
     354             : 
     355             : already_AddRefed<nsContentList>
     356           0 : NS_GetFuncStringHTMLCollection(nsINode* aRootNode,
     357             :                                nsContentListMatchFunc aFunc,
     358             :                                nsContentListDestroyFunc aDestroyFunc,
     359             :                                nsFuncStringContentListDataAllocator aDataAllocator,
     360             :                                const nsAString& aString)
     361             : {
     362             :   return GetFuncStringContentList<nsCacheableFuncStringHTMLCollection>(aRootNode,
     363             :                                                                        aFunc,
     364             :                                                                        aDestroyFunc,
     365             :                                                                        aDataAllocator,
     366           0 :                                                                        aString);
     367             : }
     368             : 
     369             : //-----------------------------------------------------
     370             : // nsContentList implementation
     371             : 
     372           8 : nsContentList::nsContentList(nsINode* aRootNode,
     373             :                              int32_t aMatchNameSpaceId,
     374             :                              nsIAtom* aHTMLMatchAtom,
     375             :                              nsIAtom* aXMLMatchAtom,
     376           8 :                              bool aDeep)
     377             :   : nsBaseContentList(),
     378             :     mRootNode(aRootNode),
     379             :     mMatchNameSpaceId(aMatchNameSpaceId),
     380             :     mHTMLMatchAtom(aHTMLMatchAtom),
     381             :     mXMLMatchAtom(aXMLMatchAtom),
     382             :     mFunc(nullptr),
     383             :     mDestroyFunc(nullptr),
     384             :     mData(nullptr),
     385             :     mState(LIST_DIRTY),
     386             :     mDeep(aDeep),
     387             :     mFuncMayDependOnAttr(false),
     388           8 :     mIsHTMLDocument(aRootNode->OwnerDoc()->IsHTMLDocument())
     389             : {
     390           8 :   NS_ASSERTION(mRootNode, "Must have root");
     391           8 :   if (nsGkAtoms::_asterisk == mHTMLMatchAtom) {
     392           5 :     NS_ASSERTION(mXMLMatchAtom == nsGkAtoms::_asterisk, "HTML atom and XML atom are not both asterisk?");
     393           5 :     mMatchAll = true;
     394             :   }
     395             :   else {
     396           3 :     mMatchAll = false;
     397             :   }
     398           8 :   mRootNode->AddMutationObserver(this);
     399             : 
     400             :   // We only need to flush if we're in an non-HTML document, since the
     401             :   // HTML5 parser doesn't need flushing.  Further, if we're not in a
     402             :   // document at all right now (in the GetUncomposedDoc() sense), we're
     403             :   // not parser-created and don't need to be flushing stuff under us
     404             :   // to get our kids right.
     405           8 :   nsIDocument* doc = mRootNode->GetUncomposedDoc();
     406           8 :   mFlushesNeeded = doc && !doc->IsHTMLDocument();
     407           8 : }
     408             : 
     409           2 : nsContentList::nsContentList(nsINode* aRootNode,
     410             :                              nsContentListMatchFunc aFunc,
     411             :                              nsContentListDestroyFunc aDestroyFunc,
     412             :                              void* aData,
     413             :                              bool aDeep,
     414             :                              nsIAtom* aMatchAtom,
     415             :                              int32_t aMatchNameSpaceId,
     416           2 :                              bool aFuncMayDependOnAttr)
     417             :   : nsBaseContentList(),
     418             :     mRootNode(aRootNode),
     419             :     mMatchNameSpaceId(aMatchNameSpaceId),
     420             :     mHTMLMatchAtom(aMatchAtom),
     421             :     mXMLMatchAtom(aMatchAtom),
     422             :     mFunc(aFunc),
     423             :     mDestroyFunc(aDestroyFunc),
     424             :     mData(aData),
     425             :     mState(LIST_DIRTY),
     426             :     mMatchAll(false),
     427             :     mDeep(aDeep),
     428             :     mFuncMayDependOnAttr(aFuncMayDependOnAttr),
     429           2 :     mIsHTMLDocument(false)
     430             : {
     431           2 :   NS_ASSERTION(mRootNode, "Must have root");
     432           2 :   mRootNode->AddMutationObserver(this);
     433             : 
     434             :   // We only need to flush if we're in an non-HTML document, since the
     435             :   // HTML5 parser doesn't need flushing.  Further, if we're not in a
     436             :   // document at all right now (in the GetUncomposedDoc() sense), we're
     437             :   // not parser-created and don't need to be flushing stuff under us
     438             :   // to get our kids right.
     439           2 :   nsIDocument* doc = mRootNode->GetUncomposedDoc();
     440           2 :   mFlushesNeeded = doc && !doc->IsHTMLDocument();
     441           2 : }
     442             : 
     443           3 : nsContentList::~nsContentList()
     444             : {
     445           1 :   RemoveFromHashtable();
     446           1 :   if (mRootNode) {
     447           0 :     mRootNode->RemoveMutationObserver(this);
     448             :   }
     449             : 
     450           1 :   if (mDestroyFunc) {
     451             :     // Clean up mData
     452           0 :     (*mDestroyFunc)(mData);
     453             :   }
     454           3 : }
     455             : 
     456             : JSObject*
     457           9 : nsContentList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
     458             : {
     459           9 :   return HTMLCollectionBinding::Wrap(cx, this, aGivenProto);
     460             : }
     461             : 
     462          58 : NS_IMPL_ISUPPORTS_INHERITED(nsContentList, nsBaseContentList,
     463             :                             nsIHTMLCollection, nsIDOMHTMLCollection,
     464             :                             nsIMutationObserver)
     465             : 
     466             : uint32_t
     467          42 : nsContentList::Length(bool aDoFlush)
     468             : {
     469          42 :   BringSelfUpToDate(aDoFlush);
     470             : 
     471          42 :   return mElements.Length();
     472             : }
     473             : 
     474             : nsIContent *
     475          41 : nsContentList::Item(uint32_t aIndex, bool aDoFlush)
     476             : {
     477          41 :   if (mRootNode && aDoFlush && mFlushesNeeded) {
     478             :     // XXX sXBL/XBL2 issue
     479          17 :     nsIDocument* doc = mRootNode->GetUncomposedDoc();
     480          17 :     if (doc) {
     481             :       // Flush pending content changes Bug 4891.
     482          17 :       doc->FlushPendingNotifications(FlushType::ContentAndNotify);
     483             :     }
     484             :   }
     485             : 
     486          41 :   if (mState != LIST_UP_TO_DATE)
     487           4 :     PopulateSelf(std::min(aIndex, UINT32_MAX - 1) + 1);
     488             : 
     489             :   ASSERT_IN_SYNC;
     490          41 :   NS_ASSERTION(!mRootNode || mState != LIST_DIRTY,
     491             :                "PopulateSelf left the list in a dirty (useless) state!");
     492             : 
     493          41 :   return mElements.SafeElementAt(aIndex);
     494             : }
     495             : 
     496             : Element*
     497           0 : nsContentList::NamedItem(const nsAString& aName, bool aDoFlush)
     498             : {
     499           0 :   if (aName.IsEmpty()) {
     500           0 :     return nullptr;
     501             :   }
     502             : 
     503           0 :   BringSelfUpToDate(aDoFlush);
     504             : 
     505           0 :   uint32_t i, count = mElements.Length();
     506             : 
     507             :   // Typically IDs and names are atomized
     508           0 :   nsCOMPtr<nsIAtom> name = NS_Atomize(aName);
     509           0 :   NS_ENSURE_TRUE(name, nullptr);
     510             : 
     511           0 :   for (i = 0; i < count; i++) {
     512           0 :     nsIContent *content = mElements[i];
     513             :     // XXX Should this pass eIgnoreCase?
     514           0 :     if (content &&
     515           0 :         ((content->IsHTMLElement() &&
     516           0 :           content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
     517           0 :                                name, eCaseMatters)) ||
     518           0 :          content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id,
     519             :                               name, eCaseMatters))) {
     520           0 :       return content->AsElement();
     521             :     }
     522             :   }
     523             : 
     524           0 :   return nullptr;
     525             : }
     526             : 
     527             : void
     528           0 : nsContentList::GetSupportedNames(nsTArray<nsString>& aNames)
     529             : {
     530           0 :   BringSelfUpToDate(true);
     531             : 
     532           0 :   AutoTArray<nsIAtom*, 8> atoms;
     533           0 :   for (uint32_t i = 0; i < mElements.Length(); ++i) {
     534           0 :     nsIContent *content = mElements.ElementAt(i);
     535           0 :     if (content->HasID()) {
     536           0 :       nsIAtom* id = content->GetID();
     537           0 :       MOZ_ASSERT(id != nsGkAtoms::_empty,
     538             :                  "Empty ids don't get atomized");
     539           0 :       if (!atoms.Contains(id)) {
     540           0 :         atoms.AppendElement(id);
     541             :       }
     542             :     }
     543             : 
     544           0 :     nsGenericHTMLElement* el = nsGenericHTMLElement::FromContent(content);
     545           0 :     if (el) {
     546             :       // XXXbz should we be checking for particular tags here?  How
     547             :       // stable is this part of the spec?
     548             :       // Note: nsINode::HasName means the name is exposed on the document,
     549             :       // which is false for options, so we don't check it here.
     550           0 :       const nsAttrValue* val = el->GetParsedAttr(nsGkAtoms::name);
     551           0 :       if (val && val->Type() == nsAttrValue::eAtom) {
     552           0 :         nsIAtom* name = val->GetAtomValue();
     553           0 :         MOZ_ASSERT(name != nsGkAtoms::_empty,
     554             :                    "Empty names don't get atomized");
     555           0 :         if (!atoms.Contains(name)) {
     556           0 :           atoms.AppendElement(name);
     557             :         }
     558             :       }
     559             :     }
     560             :   }
     561             : 
     562           0 :   uint32_t atomsLen = atoms.Length();
     563           0 :   nsString* names = aNames.AppendElements(atomsLen);
     564           0 :   for (uint32_t i = 0; i < atomsLen; ++i) {
     565           0 :     atoms[i]->ToString(names[i]);
     566             :   }
     567           0 : }
     568             : 
     569             : int32_t
     570           0 : nsContentList::IndexOf(nsIContent *aContent, bool aDoFlush)
     571             : {
     572           0 :   BringSelfUpToDate(aDoFlush);
     573             : 
     574           0 :   return mElements.IndexOf(aContent);
     575             : }
     576             : 
     577             : int32_t
     578           0 : nsContentList::IndexOf(nsIContent* aContent)
     579             : {
     580           0 :   return IndexOf(aContent, true);
     581             : }
     582             : 
     583             : void
     584           0 : nsContentList::NodeWillBeDestroyed(const nsINode* aNode)
     585             : {
     586             :   // We shouldn't do anything useful from now on
     587             : 
     588           0 :   RemoveFromCaches();
     589           0 :   mRootNode = nullptr;
     590             : 
     591             :   // We will get no more updates, so we can never know we're up to
     592             :   // date
     593           0 :   SetDirty();
     594           0 : }
     595             : 
     596             : void
     597           1 : nsContentList::LastRelease()
     598             : {
     599           1 :   RemoveFromCaches();
     600           1 :   if (mRootNode) {
     601           1 :     mRootNode->RemoveMutationObserver(this);
     602           1 :     mRootNode = nullptr;
     603             :   }
     604           1 :   SetDirty();
     605           1 : }
     606             : 
     607             : NS_IMETHODIMP
     608          42 : nsContentList::GetLength(uint32_t* aLength)
     609             : {
     610          42 :   *aLength = Length(true);
     611             : 
     612          42 :   return NS_OK;
     613             : }
     614             : 
     615             : NS_IMETHODIMP
     616           0 : nsContentList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
     617             : {
     618           0 :   nsINode* node = Item(aIndex);
     619             : 
     620           0 :   if (node) {
     621           0 :     return CallQueryInterface(node, aReturn);
     622             :   }
     623             : 
     624           0 :   *aReturn = nullptr;
     625             : 
     626           0 :   return NS_OK;
     627             : }
     628             : 
     629             : NS_IMETHODIMP
     630           0 : nsContentList::NamedItem(const nsAString& aName, nsIDOMNode** aReturn)
     631             : {
     632           0 :   nsIContent *content = NamedItem(aName, true);
     633             : 
     634           0 :   if (content) {
     635           0 :     return CallQueryInterface(content, aReturn);
     636             :   }
     637             : 
     638           0 :   *aReturn = nullptr;
     639             : 
     640           0 :   return NS_OK;
     641             : }
     642             : 
     643             : Element*
     644          40 : nsContentList::GetElementAt(uint32_t aIndex)
     645             : {
     646          40 :   return static_cast<Element*>(Item(aIndex, true));
     647             : }
     648             : 
     649             : nsIContent*
     650           0 : nsContentList::Item(uint32_t aIndex)
     651             : {
     652           0 :   return GetElementAt(aIndex);
     653             : }
     654             : 
     655             : void
     656         104 : nsContentList::AttributeChanged(nsIDocument *aDocument, Element* aElement,
     657             :                                 int32_t aNameSpaceID, nsIAtom* aAttribute,
     658             :                                 int32_t aModType,
     659             :                                 const nsAttrValue* aOldValue)
     660             : {
     661         104 :   NS_PRECONDITION(aElement, "Must have a content node to work with");
     662             : 
     663         208 :   if (!mFunc || !mFuncMayDependOnAttr || mState == LIST_DIRTY ||
     664         104 :       !MayContainRelevantNodes(aElement->GetParentNode()) ||
     665           0 :       !nsContentUtils::IsInSameAnonymousTree(mRootNode, aElement)) {
     666             :     // Either we're already dirty or this notification doesn't affect
     667             :     // whether we might match aElement.
     668         104 :     return;
     669             :   }
     670             : 
     671           0 :   if (Match(aElement)) {
     672           0 :     if (mElements.IndexOf(aElement) == mElements.NoIndex) {
     673             :       // We match aElement now, and it's not in our list already.  Just dirty
     674             :       // ourselves; this is simpler than trying to figure out where to insert
     675             :       // aElement.
     676           0 :       SetDirty();
     677             :     }
     678             :   } else {
     679             :     // We no longer match aElement.  Remove it from our list.  If it's
     680             :     // already not there, this is a no-op (though a potentially
     681             :     // expensive one).  Either way, no change of mState is required
     682             :     // here.
     683           0 :     mElements.RemoveElement(aElement);
     684             :   }
     685             : }
     686             : 
     687             : void
     688          10 : nsContentList::ContentAppended(nsIDocument* aDocument, nsIContent* aContainer,
     689             :                                nsIContent* aFirstNewContent,
     690             :                                int32_t aNewIndexInContainer)
     691             : {
     692          10 :   NS_PRECONDITION(aContainer, "Can't get at the new content if no container!");
     693             : 
     694             :   /*
     695             :    * If the state is LIST_DIRTY then we have no useful information in our list
     696             :    * and we want to put off doing work as much as possible.
     697             :    *
     698             :    * Also, if aContainer is anonymous from our point of view, we know that we
     699             :    * can't possibly be matching any of the kids.
     700             :    *
     701             :    * Optimize out also the common case when just one new node is appended and
     702             :    * it doesn't match us.
     703             :    */
     704          30 :   if (mState == LIST_DIRTY ||
     705          17 :       !nsContentUtils::IsInSameAnonymousTree(mRootNode, aContainer) ||
     706          29 :       !MayContainRelevantNodes(aContainer) ||
     707           4 :       (!aFirstNewContent->HasChildren() &&
     708           4 :        !aFirstNewContent->GetNextSibling() &&
     709           2 :        !MatchSelf(aFirstNewContent))) {
     710          10 :     return;
     711             :   }
     712             : 
     713             :   /*
     714             :    * We want to handle the case of ContentAppended by sometimes
     715             :    * appending the content to our list, not just setting state to
     716             :    * LIST_DIRTY, since most of our ContentAppended notifications
     717             :    * should come during pageload and be at the end of the document.
     718             :    * Do a bit of work to see whether we could just append to what we
     719             :    * already have.
     720             :    */
     721             : 
     722           0 :   int32_t count = aContainer->GetChildCount();
     723             : 
     724           0 :   if (count > 0) {
     725           0 :     uint32_t ourCount = mElements.Length();
     726           0 :     bool appendToList = false;
     727           0 :     if (ourCount == 0) {
     728           0 :       appendToList = true;
     729             :     } else {
     730           0 :       nsIContent* ourLastContent = mElements[ourCount - 1];
     731             :       /*
     732             :        * We want to append instead of invalidating if the first thing
     733             :        * that got appended comes after ourLastContent.
     734             :        */
     735           0 :       if (nsContentUtils::PositionIsBefore(ourLastContent, aFirstNewContent)) {
     736           0 :         appendToList = true;
     737             :       }
     738             :     }
     739             : 
     740             : 
     741           0 :     if (!appendToList) {
     742             :       // The new stuff is somewhere in the middle of our list; check
     743             :       // whether we need to invalidate
     744           0 :       for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
     745           0 :         if (MatchSelf(cur)) {
     746             :           // Uh-oh.  We're gonna have to add elements into the middle
     747             :           // of our list. That's not worth the effort.
     748           0 :           SetDirty();
     749           0 :           break;
     750             :         }
     751             :       }
     752             : 
     753             :       ASSERT_IN_SYNC;
     754           0 :       return;
     755             :     }
     756             : 
     757             :     /*
     758             :      * At this point we know we could append.  If we're not up to
     759             :      * date, however, that would be a bad idea -- it could miss some
     760             :      * content that we never picked up due to being lazy.  Further, we
     761             :      * may never get asked for this content... so don't grab it yet.
     762             :      */
     763           0 :     if (mState == LIST_LAZY) // be lazy
     764           0 :       return;
     765             : 
     766             :     /*
     767             :      * We're up to date.  That means someone's actively using us; we
     768             :      * may as well grab this content....
     769             :      */
     770           0 :     if (mDeep) {
     771           0 :       for (nsIContent* cur = aFirstNewContent;
     772           0 :            cur;
     773           0 :            cur = cur->GetNextNode(aContainer)) {
     774           0 :         if (cur->IsElement() && Match(cur->AsElement())) {
     775           0 :           mElements.AppendElement(cur);
     776             :         }
     777             :       }
     778             :     } else {
     779           0 :       for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
     780           0 :         if (cur->IsElement() && Match(cur->AsElement())) {
     781           0 :           mElements.AppendElement(cur);
     782             :         }
     783             :       }
     784             :     }
     785             : 
     786             :     ASSERT_IN_SYNC;
     787             :   }
     788             : }
     789             : 
     790             : void
     791          13 : nsContentList::ContentInserted(nsIDocument *aDocument,
     792             :                                nsIContent* aContainer,
     793             :                                nsIContent* aChild,
     794             :                                int32_t aIndexInContainer)
     795             : {
     796             :   // Note that aContainer can be null here if we are inserting into
     797             :   // the document itself; any attempted optimizations to this method
     798             :   // should deal with that.
     799          39 :   if (mState != LIST_DIRTY &&
     800          13 :       MayContainRelevantNodes(NODE_FROM(aContainer, aDocument)) &&
     801          13 :       nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild) &&
     802           0 :       MatchSelf(aChild)) {
     803           0 :     SetDirty();
     804             :   }
     805             : 
     806             :   ASSERT_IN_SYNC;
     807          13 : }
     808             : 
     809             : void
     810          28 : nsContentList::ContentRemoved(nsIDocument *aDocument,
     811             :                               nsIContent* aContainer,
     812             :                               nsIContent* aChild,
     813             :                               int32_t aIndexInContainer,
     814             :                               nsIContent* aPreviousSibling)
     815             : {
     816             :   // Note that aContainer can be null here if we are removing from
     817             :   // the document itself; any attempted optimizations to this method
     818             :   // should deal with that.
     819          64 :   if (mState != LIST_DIRTY &&
     820          12 :       MayContainRelevantNodes(NODE_FROM(aContainer, aDocument)) &&
     821          36 :       nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild) &&
     822           4 :       MatchSelf(aChild)) {
     823           3 :     SetDirty();
     824             :   }
     825             : 
     826             :   ASSERT_IN_SYNC;
     827          28 : }
     828             : 
     829             : bool
     830          62 : nsContentList::Match(Element *aElement)
     831             : {
     832          62 :   if (mFunc) {
     833           4 :     return (*mFunc)(aElement, mMatchNameSpaceId, mXMLMatchAtom, mData);
     834             :   }
     835             : 
     836          58 :   if (!mXMLMatchAtom)
     837           0 :     return false;
     838             : 
     839          58 :   NodeInfo *ni = aElement->NodeInfo();
     840             : 
     841          58 :   bool unknown = mMatchNameSpaceId == kNameSpaceID_Unknown;
     842          58 :   bool wildcard = mMatchNameSpaceId == kNameSpaceID_Wildcard;
     843          58 :   bool toReturn = mMatchAll;
     844          58 :   if (!unknown && !wildcard)
     845           8 :     toReturn &= ni->NamespaceEquals(mMatchNameSpaceId);
     846             : 
     847          58 :   if (toReturn)
     848          45 :     return toReturn;
     849             : 
     850             :   bool matchHTML =
     851          13 :     mIsHTMLDocument && aElement->GetNameSpaceID() == kNameSpaceID_XHTML;
     852             : 
     853          13 :   if (unknown) {
     854          10 :     return matchHTML ? ni->QualifiedNameEquals(mHTMLMatchAtom) :
     855          10 :                        ni->QualifiedNameEquals(mXMLMatchAtom);
     856             :   }
     857             : 
     858           8 :   if (wildcard) {
     859           0 :     return matchHTML ? ni->Equals(mHTMLMatchAtom) :
     860           0 :                        ni->Equals(mXMLMatchAtom);
     861             :   }
     862             : 
     863          12 :   return matchHTML ? ni->Equals(mHTMLMatchAtom, mMatchNameSpaceId) :
     864          12 :                      ni->Equals(mXMLMatchAtom, mMatchNameSpaceId);
     865             : }
     866             : 
     867             : bool
     868           6 : nsContentList::MatchSelf(nsIContent *aContent)
     869             : {
     870           6 :   NS_PRECONDITION(aContent, "Can't match null stuff, you know");
     871           6 :   NS_PRECONDITION(mDeep || aContent->GetParentNode() == mRootNode,
     872             :                   "MatchSelf called on a node that we can't possibly match");
     873             : 
     874           6 :   if (!aContent->IsElement()) {
     875           0 :     return false;
     876             :   }
     877             : 
     878           6 :   if (Match(aContent->AsElement()))
     879           3 :     return true;
     880             : 
     881           3 :   if (!mDeep)
     882           0 :     return false;
     883             : 
     884           3 :   for (nsIContent* cur = aContent->GetFirstChild();
     885           3 :        cur;
     886           0 :        cur = cur->GetNextNode(aContent)) {
     887           0 :     if (cur->IsElement() && Match(cur->AsElement())) {
     888           0 :       return true;
     889             :     }
     890             :   }
     891             : 
     892           3 :   return false;
     893             : }
     894             : 
     895             : void
     896          11 : nsContentList::PopulateSelf(uint32_t aNeededLength)
     897             : {
     898          11 :   if (!mRootNode) {
     899           0 :     return;
     900             :   }
     901             : 
     902             :   ASSERT_IN_SYNC;
     903             : 
     904          11 :   uint32_t count = mElements.Length();
     905          11 :   NS_ASSERTION(mState != LIST_DIRTY || count == 0,
     906             :                "Reset() not called when setting state to LIST_DIRTY?");
     907             : 
     908          11 :   if (count >= aNeededLength) // We're all set
     909           0 :     return;
     910             : 
     911          11 :   uint32_t elementsToAppend = aNeededLength - count;
     912             : #ifdef DEBUG
     913          11 :   uint32_t invariant = elementsToAppend + mElements.Length();
     914             : #endif
     915             : 
     916          11 :   if (mDeep) {
     917             :     // If we already have nodes start searching at the last one, otherwise
     918             :     // start searching at the root.
     919           5 :     nsINode* cur = count ? mElements[count - 1] : mRootNode;
     920          14 :     do {
     921          19 :       cur = cur->GetNextNode(mRootNode);
     922          19 :       if (!cur) {
     923           3 :         break;
     924             :       }
     925          16 :       if (cur->IsElement() && Match(cur->AsElement())) {
     926             :         // Append AsElement() to get nsIContent instead of nsINode
     927           2 :         mElements.AppendElement(cur->AsElement());
     928           2 :         --elementsToAppend;
     929             :       }
     930          16 :     } while (elementsToAppend);
     931             :   } else {
     932             :     nsIContent* cur =
     933           6 :       count ? mElements[count-1]->GetNextSibling() : mRootNode->GetFirstChild();
     934          90 :     for ( ; cur && elementsToAppend; cur = cur->GetNextSibling()) {
     935          42 :       if (cur->IsElement() && Match(cur->AsElement())) {
     936          42 :         mElements.AppendElement(cur);
     937          42 :         --elementsToAppend;
     938             :       }
     939             :     }
     940             :   }
     941             : 
     942          11 :   NS_ASSERTION(elementsToAppend + mElements.Length() == invariant,
     943             :                "Something is awry!");
     944             : 
     945          11 :   if (elementsToAppend != 0)
     946           9 :     mState = LIST_UP_TO_DATE;
     947             :   else
     948           2 :     mState = LIST_LAZY;
     949             : 
     950             :   ASSERT_IN_SYNC;
     951             : }
     952             : 
     953             : void
     954           2 : nsContentList::RemoveFromHashtable()
     955             : {
     956           2 :   if (mFunc) {
     957             :     // This can't be in the table anyway
     958           0 :     return;
     959             :   }
     960             : 
     961           4 :   nsDependentAtomString str(mXMLMatchAtom);
     962           2 :   nsContentListKey key(mRootNode, mMatchNameSpaceId, str, mIsHTMLDocument);
     963           2 :   uint32_t recentlyUsedCacheIndex = RecentlyUsedCacheIndex(key);
     964           2 :   if (sRecentlyUsedContentLists[recentlyUsedCacheIndex] == this) {
     965           1 :     sRecentlyUsedContentLists[recentlyUsedCacheIndex] = nullptr;
     966             :   }
     967             : 
     968           2 :   if (!gContentListHashTable)
     969           0 :     return;
     970             : 
     971           2 :   gContentListHashTable->Remove(&key);
     972             : 
     973           2 :   if (gContentListHashTable->EntryCount() == 0) {
     974           1 :     delete gContentListHashTable;
     975           1 :     gContentListHashTable = nullptr;
     976             :   }
     977             : }
     978             : 
     979             : void
     980          42 : nsContentList::BringSelfUpToDate(bool aDoFlush)
     981             : {
     982          42 :   if (mRootNode && aDoFlush && mFlushesNeeded) {
     983             :     // XXX sXBL/XBL2 issue
     984          18 :     nsIDocument* doc = mRootNode->GetUncomposedDoc();
     985          18 :     if (doc) {
     986             :       // Flush pending content changes Bug 4891.
     987          18 :       doc->FlushPendingNotifications(FlushType::ContentAndNotify);
     988             :     }
     989             :   }
     990             : 
     991          42 :   if (mState != LIST_UP_TO_DATE)
     992           7 :     PopulateSelf(uint32_t(-1));
     993             : 
     994             :   ASSERT_IN_SYNC;
     995          42 :   NS_ASSERTION(!mRootNode || mState == LIST_UP_TO_DATE,
     996             :                "PopulateSelf dod not bring content list up to date!");
     997          42 : }
     998             : 
     999           0 : nsCacheableFuncStringContentList::~nsCacheableFuncStringContentList()
    1000             : {
    1001           0 :   RemoveFromFuncStringHashtable();
    1002           0 : }
    1003             : 
    1004             : void
    1005           0 : nsCacheableFuncStringContentList::RemoveFromFuncStringHashtable()
    1006             : {
    1007           0 :   if (!gFuncStringContentListHashTable) {
    1008           0 :     return;
    1009             :   }
    1010             : 
    1011           0 :   nsFuncStringCacheKey key(mRootNode, mFunc, mString);
    1012           0 :   gFuncStringContentListHashTable->Remove(&key);
    1013             : 
    1014           0 :   if (gFuncStringContentListHashTable->EntryCount() == 0) {
    1015           0 :     delete gFuncStringContentListHashTable;
    1016           0 :     gFuncStringContentListHashTable = nullptr;
    1017             :   }
    1018             : }
    1019             : 
    1020             : #ifdef DEBUG_CONTENT_LIST
    1021             : void
    1022             : nsContentList::AssertInSync()
    1023             : {
    1024             :   if (mState == LIST_DIRTY) {
    1025             :     return;
    1026             :   }
    1027             : 
    1028             :   if (!mRootNode) {
    1029             :     NS_ASSERTION(mElements.Length() == 0 && mState == LIST_DIRTY,
    1030             :                  "Empty iterator isn't quite empty?");
    1031             :     return;
    1032             :   }
    1033             : 
    1034             :   // XXX This code will need to change if nsContentLists can ever match
    1035             :   // elements that are outside of the document element.
    1036             :   nsIContent *root;
    1037             :   if (mRootNode->IsNodeOfType(nsINode::eDOCUMENT)) {
    1038             :     root = static_cast<nsIDocument*>(mRootNode)->GetRootElement();
    1039             :   }
    1040             :   else {
    1041             :     root = static_cast<nsIContent*>(mRootNode);
    1042             :   }
    1043             : 
    1044             :   nsCOMPtr<nsIContentIterator> iter;
    1045             :   if (mDeep) {
    1046             :     iter = NS_NewPreContentIterator();
    1047             :     iter->Init(root);
    1048             :     iter->First();
    1049             :   }
    1050             : 
    1051             :   uint32_t cnt = 0, index = 0;
    1052             :   while (true) {
    1053             :     if (cnt == mElements.Length() && mState == LIST_LAZY) {
    1054             :       break;
    1055             :     }
    1056             : 
    1057             :     nsIContent *cur = mDeep ? iter->GetCurrentNode() :
    1058             :                               mRootNode->GetChildAt(index++);
    1059             :     if (!cur) {
    1060             :       break;
    1061             :     }
    1062             : 
    1063             :     if (cur->IsElement() && Match(cur->AsElement())) {
    1064             :       NS_ASSERTION(cnt < mElements.Length() && mElements[cnt] == cur,
    1065             :                    "Elements is out of sync");
    1066             :       ++cnt;
    1067             :     }
    1068             : 
    1069             :     if (mDeep) {
    1070             :       iter->Next();
    1071             :     }
    1072             :   }
    1073             : 
    1074             :   NS_ASSERTION(cnt == mElements.Length(), "Too few elements");
    1075             : }
    1076             : #endif
    1077             : 
    1078             : //-----------------------------------------------------
    1079             : // nsCacheableFuncStringNodeList
    1080             : 
    1081             : JSObject*
    1082           0 : nsCacheableFuncStringNodeList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
    1083             : {
    1084           0 :   return NodeListBinding::Wrap(cx, this, aGivenProto);
    1085             : }
    1086             : 
    1087             : //-----------------------------------------------------
    1088             : // nsCacheableFuncStringHTMLCollection
    1089             : 
    1090             : JSObject*
    1091           0 : nsCacheableFuncStringHTMLCollection::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
    1092             : {
    1093           0 :   return HTMLCollectionBinding::Wrap(cx, this, aGivenProto);
    1094             : }
    1095             : 
    1096             : //-----------------------------------------------------
    1097             : // nsLabelsNodeList
    1098             : 
    1099             : JSObject*
    1100           0 : nsLabelsNodeList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
    1101             : {
    1102           0 :   return NodeListBinding::Wrap(cx, this, aGivenProto);
    1103             : }
    1104             : 
    1105             : void
    1106           0 : nsLabelsNodeList::AttributeChanged(nsIDocument* aDocument, Element* aElement,
    1107             :                                    int32_t aNameSpaceID, nsIAtom* aAttribute,
    1108             :                                    int32_t aModType,
    1109             :                                    const nsAttrValue* aOldValue)
    1110             : {
    1111           0 :   MOZ_ASSERT(aElement, "Must have a content node to work with");
    1112           0 :   if (mState == LIST_DIRTY ||
    1113           0 :       !nsContentUtils::IsInSameAnonymousTree(mRootNode, aElement)) {
    1114           0 :     return;
    1115             :   }
    1116             : 
    1117             :   // We need to handle input type changes to or from "hidden".
    1118           0 :   if (aElement->IsHTMLElement(nsGkAtoms::input) &&
    1119           0 :       aAttribute == nsGkAtoms::type && aNameSpaceID == kNameSpaceID_None) {
    1120           0 :     SetDirty();
    1121           0 :     return;
    1122             :   }
    1123             : }
    1124             : 
    1125             : void
    1126           0 : nsLabelsNodeList::ContentAppended(nsIDocument* aDocument,
    1127             :                                   nsIContent* aContainer,
    1128             :                                   nsIContent* aFirstNewContent,
    1129             :                                   int32_t aNewIndexInContainer)
    1130             : {
    1131             :   // If a labelable element is moved to outside or inside of
    1132             :   // nested associated labels, we're gonna have to modify
    1133             :   // the content list.
    1134           0 :   if (mState != LIST_DIRTY ||
    1135           0 :       nsContentUtils::IsInSameAnonymousTree(mRootNode, aContainer)) {
    1136           0 :     SetDirty();
    1137           0 :     return;
    1138             :   }
    1139             : }
    1140             : 
    1141             : void
    1142           0 : nsLabelsNodeList::ContentInserted(nsIDocument* aDocument,
    1143             :                                   nsIContent* aContainer,
    1144             :                                   nsIContent* aChild,
    1145             :                                   int32_t aIndexInContainer)
    1146             : {
    1147             :   // If a labelable element is moved to outside or inside of
    1148             :   // nested associated labels, we're gonna have to modify
    1149             :   // the content list.
    1150           0 :   if (mState != LIST_DIRTY ||
    1151           0 :       nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild)) {
    1152           0 :     SetDirty();
    1153           0 :     return;
    1154             :   }
    1155             : }
    1156             : 
    1157             : void
    1158           0 : nsLabelsNodeList::ContentRemoved(nsIDocument* aDocument,
    1159             :                                  nsIContent* aContainer,
    1160             :                                  nsIContent* aChild,
    1161             :                                  int32_t aIndexInContainer,
    1162             :                                  nsIContent* aPreviousSibling)
    1163             : {
    1164             :   // If a labelable element is removed, we're gonna have to clean
    1165             :   // the content list.
    1166           0 :   if (mState != LIST_DIRTY ||
    1167           0 :       nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild)) {
    1168           0 :     SetDirty();
    1169           0 :     return;
    1170             :   }
    1171             : }
    1172             : 
    1173             : void
    1174           0 : nsLabelsNodeList::MaybeResetRoot(nsINode* aRootNode)
    1175             : {
    1176           0 :   MOZ_ASSERT(aRootNode, "Must have root");
    1177           0 :   if (mRootNode == aRootNode) {
    1178           0 :     return;
    1179             :   }
    1180             : 
    1181           0 :   if (mRootNode) {
    1182           0 :     mRootNode->RemoveMutationObserver(this);
    1183             :   }
    1184           0 :   mRootNode = aRootNode;
    1185           0 :   mRootNode->AddMutationObserver(this);
    1186           0 :   SetDirty();
    1187             : }
    1188             : 
    1189             : void
    1190           0 : nsLabelsNodeList::PopulateSelf(uint32_t aNeededLength)
    1191             : {
    1192           0 :   MOZ_ASSERT(mRootNode, "Must have root");
    1193             : 
    1194             :   // Start searching at the root.
    1195           0 :   nsINode* cur = mRootNode;
    1196           0 :   if (mElements.IsEmpty() && cur->IsElement() && Match(cur->AsElement())) {
    1197           0 :     mElements.AppendElement(cur->AsElement());
    1198             :   }
    1199             : 
    1200           0 :   nsContentList::PopulateSelf(aNeededLength);
    1201           0 : }

Generated by: LCOV version 1.13