content/base/src/nsContentList.h

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /*
     7  * nsBaseContentList is a basic list of content nodes; nsContentList
     8  * is a commonly used NodeList implementation (used for
     9  * getElementsByTagName, some properties on nsIDOMHTMLDocument, etc).
    10  */
    12 #ifndef nsContentList_h___
    13 #define nsContentList_h___
    15 #include "mozilla/Attributes.h"
    16 #include "nsContentListDeclarations.h"
    17 #include "nsISupports.h"
    18 #include "nsTArray.h"
    19 #include "nsString.h"
    20 #include "nsIHTMLCollection.h"
    21 #include "nsIDOMNodeList.h"
    22 #include "nsINodeList.h"
    23 #include "nsStubMutationObserver.h"
    24 #include "nsIAtom.h"
    25 #include "nsCycleCollectionParticipant.h"
    26 #include "nsNameSpaceManager.h"
    27 #include "nsWrapperCache.h"
    28 #include "nsHashKeys.h"
    29 #include "mozilla/HashFunctions.h"
    31 namespace mozilla {
    32 namespace dom {
    33 class Element;
    34 }
    35 }
    38 class nsBaseContentList : public nsINodeList
    39 {
    40 public:
    41   nsBaseContentList()
    42   {
    43     SetIsDOMBinding();
    44   }
    45   virtual ~nsBaseContentList();
    47   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    49   // nsIDOMNodeList
    50   NS_DECL_NSIDOMNODELIST
    52   // nsINodeList
    53   virtual int32_t IndexOf(nsIContent* aContent) MOZ_OVERRIDE;
    54   virtual nsIContent* Item(uint32_t aIndex) MOZ_OVERRIDE;
    56   uint32_t Length() const { 
    57     return mElements.Length();
    58   }
    60   NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsBaseContentList)
    62   void AppendElement(nsIContent *aContent)
    63   {
    64     mElements.AppendElement(aContent);
    65   }
    66   void MaybeAppendElement(nsIContent* aContent)
    67   {
    68     if (aContent)
    69       AppendElement(aContent);
    70   }
    72   /**
    73    * Insert the element at a given index, shifting the objects at
    74    * the given index and later to make space.
    75    * @param aContent Element to insert, must not be null
    76    * @param aIndex Index to insert the element at.
    77    */
    78   void InsertElementAt(nsIContent* aContent, int32_t aIndex)
    79   {
    80     NS_ASSERTION(aContent, "Element to insert must not be null");
    81     mElements.InsertElementAt(aIndex, aContent);
    82   }
    84   void RemoveElement(nsIContent *aContent)
    85   {
    86     mElements.RemoveElement(aContent);
    87   }
    89   void Reset() {
    90     mElements.Clear();
    91   }
    93   virtual int32_t IndexOf(nsIContent *aContent, bool aDoFlush);
    95   virtual JSObject* WrapObject(JSContext *cx)
    96     MOZ_OVERRIDE = 0;
    98   void SetCapacity(uint32_t aCapacity)
    99   {
   100     mElements.SetCapacity(aCapacity);
   101   }
   102 protected:
   103   /**
   104    * To be called from non-destructor locations (e.g. unlink) that want to
   105    * remove from caches.  Cacheable subclasses should override.
   106    */
   107   virtual void RemoveFromCaches()
   108   {
   109   }
   111   nsTArray< nsCOMPtr<nsIContent> > mElements;
   112 };
   115 class nsSimpleContentList : public nsBaseContentList
   116 {
   117 public:
   118   nsSimpleContentList(nsINode *aRoot) : nsBaseContentList(),
   119                                         mRoot(aRoot)
   120   {
   121   }
   123   NS_DECL_ISUPPORTS_INHERITED
   124   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsSimpleContentList,
   125                                            nsBaseContentList)
   127   virtual nsINode* GetParentObject() MOZ_OVERRIDE
   128   {
   129     return mRoot;
   130   }
   131   virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
   133 private:
   134   // This has to be a strong reference, the root might go away before the list.
   135   nsCOMPtr<nsINode> mRoot;
   136 };
   138 /**
   139  * Class that's used as the key to hash nsContentList implementations
   140  * for fast retrieval
   141  */
   142 struct nsContentListKey
   143 {
   144   nsContentListKey(nsINode* aRootNode,
   145                    int32_t aMatchNameSpaceId,
   146                    const nsAString& aTagname)
   147     : mRootNode(aRootNode),
   148       mMatchNameSpaceId(aMatchNameSpaceId),
   149       mTagname(aTagname),
   150       mHash(mozilla::AddToHash(mozilla::HashString(aTagname), mRootNode,
   151                                mMatchNameSpaceId))
   152   {
   153   }
   155   nsContentListKey(const nsContentListKey& aContentListKey)
   156     : mRootNode(aContentListKey.mRootNode),
   157       mMatchNameSpaceId(aContentListKey.mMatchNameSpaceId),
   158       mTagname(aContentListKey.mTagname),
   159       mHash(aContentListKey.mHash)
   160   {
   161   }
   163   inline uint32_t GetHash(void) const
   164   {
   165     return mHash;
   166   }
   168   nsINode* const mRootNode; // Weak ref
   169   const int32_t mMatchNameSpaceId;
   170   const nsAString& mTagname;
   171   const uint32_t mHash;
   172 };
   174 /**
   175  * LIST_UP_TO_DATE means that the list is up to date and need not do
   176  * any walking to be able to answer any questions anyone may have.
   177  */
   178 #define LIST_UP_TO_DATE 0
   179 /**
   180  * LIST_DIRTY means that the list contains no useful information and
   181  * if anyone asks it anything it will have to populate itself before
   182  * answering.
   183  */
   184 #define LIST_DIRTY 1
   185 /**
   186  * LIST_LAZY means that the list has populated itself to a certain
   187  * extent and that that part of the list is still valid.  Requests for
   188  * things outside that part of the list will require walking the tree
   189  * some more.  When a list is in this state, the last thing in
   190  * mElements is the last node in the tree that the list looked at.
   191  */
   192 #define LIST_LAZY 2
   194 /**
   195  * Class that implements a live NodeList that matches Elements in the
   196  * tree based on some criterion.
   197  */
   198 class nsContentList : public nsBaseContentList,
   199                       public nsIHTMLCollection,
   200                       public nsStubMutationObserver
   201 {
   202 public:
   203   NS_DECL_ISUPPORTS_INHERITED
   205   /**
   206    * @param aRootNode The node under which to limit our search.
   207    * @param aMatchAtom An atom whose meaning depends on aMatchNameSpaceId.
   208    *                   The special value "*" always matches whatever aMatchAtom
   209    *                   is matched against.
   210    * @param aMatchNameSpaceId If kNameSpaceID_Unknown, then aMatchAtom is the
   211    *                          tagName to match.
   212    *                          If kNameSpaceID_Wildcard, then aMatchAtom is the
   213    *                          localName to match.
   214    *                          Otherwise we match nodes whose namespace is
   215    *                          aMatchNameSpaceId and localName matches
   216    *                          aMatchAtom.
   217    * @param aDeep If false, then look only at children of the root, nothing
   218    *              deeper.  If true, then look at the whole subtree rooted at
   219    *              our root.
   220    */  
   221   nsContentList(nsINode* aRootNode,
   222                 int32_t aMatchNameSpaceId,
   223                 nsIAtom* aHTMLMatchAtom,
   224                 nsIAtom* aXMLMatchAtom,
   225                 bool aDeep = true);
   227   /**
   228    * @param aRootNode The node under which to limit our search.
   229    * @param aFunc the function to be called to determine whether we match.
   230    *              This function MUST NOT ever cause mutation of the DOM.
   231    *              The nsContentList implementation guarantees that everything
   232    *              passed to the function will be IsElement().
   233    * @param aDestroyFunc the function that will be called to destroy aData
   234    * @param aData closure data that will need to be passed back to aFunc
   235    * @param aDeep If false, then look only at children of the root, nothing
   236    *              deeper.  If true, then look at the whole subtree rooted at
   237    *              our root.
   238    * @param aMatchAtom an atom to be passed back to aFunc
   239    * @param aMatchNameSpaceId a namespace id to be passed back to aFunc
   240    * @param aFuncMayDependOnAttr a boolean that indicates whether this list is
   241    *                             sensitive to attribute changes.
   242    */  
   243   nsContentList(nsINode* aRootNode,
   244                 nsContentListMatchFunc aFunc,
   245                 nsContentListDestroyFunc aDestroyFunc,
   246                 void* aData,
   247                 bool aDeep = true,
   248                 nsIAtom* aMatchAtom = nullptr,
   249                 int32_t aMatchNameSpaceId = kNameSpaceID_None,
   250                 bool aFuncMayDependOnAttr = true);
   251   virtual ~nsContentList();
   253   // nsWrapperCache
   254   using nsWrapperCache::GetWrapperPreserveColor;
   255   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
   256 protected:
   257   virtual JSObject* GetWrapperPreserveColorInternal() MOZ_OVERRIDE
   258   {
   259     return nsWrapperCache::GetWrapperPreserveColor();
   260   }
   261 public:
   263   // nsIDOMHTMLCollection
   264   NS_DECL_NSIDOMHTMLCOLLECTION
   266   // nsBaseContentList overrides
   267   virtual int32_t IndexOf(nsIContent *aContent, bool aDoFlush) MOZ_OVERRIDE;
   268   virtual int32_t IndexOf(nsIContent* aContent) MOZ_OVERRIDE;
   269   virtual nsINode* GetParentObject() MOZ_OVERRIDE
   270   {
   271     return mRootNode;
   272   }
   274   virtual nsIContent* Item(uint32_t aIndex) MOZ_OVERRIDE;
   275   virtual mozilla::dom::Element* GetElementAt(uint32_t index) MOZ_OVERRIDE;
   276   virtual mozilla::dom::Element*
   277   GetFirstNamedElement(const nsAString& aName, bool& aFound) MOZ_OVERRIDE
   278   {
   279     mozilla::dom::Element* item = NamedItem(aName, true);
   280     aFound = !!item;
   281     return item;
   282   }
   283   virtual void GetSupportedNames(unsigned aFlags,
   284                                  nsTArray<nsString>& aNames) MOZ_OVERRIDE;
   286   // nsContentList public methods
   287   NS_HIDDEN_(uint32_t) Length(bool aDoFlush);
   288   NS_HIDDEN_(nsIContent*) Item(uint32_t aIndex, bool aDoFlush);
   289   NS_HIDDEN_(mozilla::dom::Element*)
   290   NamedItem(const nsAString& aName, bool aDoFlush);
   292   // nsIMutationObserver
   293   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
   294   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   295   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   296   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
   297   NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
   299   static nsContentList* FromSupports(nsISupports* aSupports)
   300   {
   301     nsINodeList* list = static_cast<nsINodeList*>(aSupports);
   302 #ifdef DEBUG
   303     {
   304       nsCOMPtr<nsINodeList> list_qi = do_QueryInterface(aSupports);
   306       // If this assertion fires the QI implementation for the object in
   307       // question doesn't use the nsINodeList pointer as the nsISupports
   308       // pointer. That must be fixed, or we'll crash...
   309       NS_ASSERTION(list_qi == list, "Uh, fix QI!");
   310     }
   311 #endif
   312     return static_cast<nsContentList*>(list);
   313   }
   315   bool MatchesKey(const nsContentListKey& aKey) const
   316   {
   317     // The root node is most commonly the same: the document.  And the
   318     // most common namespace id is kNameSpaceID_Unknown.  So check the
   319     // string first.
   320     NS_PRECONDITION(mXMLMatchAtom,
   321                     "How did we get here with a null match atom on our list?");
   322     return
   323       mXMLMatchAtom->Equals(aKey.mTagname) &&
   324       mRootNode == aKey.mRootNode &&
   325       mMatchNameSpaceId == aKey.mMatchNameSpaceId;
   326   }
   328   /**
   329    * Sets the state to LIST_DIRTY and clears mElements array.
   330    * @note This is the only acceptable way to set state to LIST_DIRTY.
   331    */
   332   void SetDirty()
   333   {
   334     mState = LIST_DIRTY;
   335     Reset();
   336   }
   338 protected:
   339   /**
   340    * Returns whether the element matches our criterion
   341    *
   342    * @param  aElement the element to attempt to match
   343    * @return whether we match
   344    */
   345   bool Match(mozilla::dom::Element *aElement);
   346   /**
   347    * See if anything in the subtree rooted at aContent, including
   348    * aContent itself, matches our criterion.
   349    *
   350    * @param  aContent the root of the subtree to match against
   351    * @return whether we match something in the tree rooted at aContent
   352    */
   353   bool MatchSelf(nsIContent *aContent);
   355   /**
   356    * Populate our list.  Stop once we have at least aNeededLength
   357    * elements.  At the end of PopulateSelf running, either the last
   358    * node we examined is the last node in our array or we have
   359    * traversed the whole document (or both).
   360    *
   361    * @param aNeededLength the length the list should have when we are
   362    *        done (unless it exhausts the document)   
   363    */
   364   void PopulateSelf(uint32_t aNeededLength);
   366   /**
   367    * @param  aContainer a content node which must be a descendant of
   368    *         mRootNode
   369    * @return true if children or descendants of aContainer could match our
   370    *                 criterion.
   371    *         false otherwise.
   372    */
   373   bool MayContainRelevantNodes(nsINode* aContainer)
   374   {
   375     return mDeep || aContainer == mRootNode;
   376   }
   378   /**
   379    * Remove ourselves from the hashtable that caches commonly accessed
   380    * content lists.  Generally done on destruction.
   381    */
   382   void RemoveFromHashtable();
   383   /**
   384    * If state is not LIST_UP_TO_DATE, fully populate ourselves with
   385    * all the nodes we can find.
   386    */
   387   inline void BringSelfUpToDate(bool aDoFlush);
   389   /**
   390    * To be called from non-destructor locations that want to remove from caches.
   391    * Needed because if subclasses want to have cache behavior they can't just
   392    * override RemoveFromHashtable(), since we call that in our destructor.
   393    */
   394   virtual void RemoveFromCaches() MOZ_OVERRIDE
   395   {
   396     RemoveFromHashtable();
   397   }
   399   nsINode* mRootNode; // Weak ref
   400   int32_t mMatchNameSpaceId;
   401   nsCOMPtr<nsIAtom> mHTMLMatchAtom;
   402   nsCOMPtr<nsIAtom> mXMLMatchAtom;
   404   /**
   405    * Function to use to determine whether a piece of content matches
   406    * our criterion
   407    */
   408   nsContentListMatchFunc mFunc;
   409   /**
   410    * Cleanup closure data with this.
   411    */
   412   nsContentListDestroyFunc mDestroyFunc;
   413   /**
   414    * Closure data to pass to mFunc when we call it
   415    */
   416   void* mData;
   417   /**
   418    * The current state of the list (possible values are:
   419    * LIST_UP_TO_DATE, LIST_LAZY, LIST_DIRTY
   420    */
   421   uint8_t mState;
   423   // The booleans have to use uint8_t to pack with mState, because MSVC won't
   424   // pack different typedefs together.  Once we no longer have to worry about
   425   // flushes in XML documents, we can go back to using bool for the
   426   // booleans.
   428   /**
   429    * True if we are looking for elements named "*"
   430    */
   431   uint8_t mMatchAll : 1;
   432   /**
   433    * Whether to actually descend the tree.  If this is false, we won't
   434    * consider grandkids of mRootNode.
   435    */
   436   uint8_t mDeep : 1;
   437   /**
   438    * Whether the return value of mFunc could depend on the values of
   439    * attributes.
   440    */
   441   uint8_t mFuncMayDependOnAttr : 1;
   442   /**
   443    * Whether we actually need to flush to get our state correct.
   444    */
   445   uint8_t mFlushesNeeded : 1;
   447 #ifdef DEBUG_CONTENT_LIST
   448   void AssertInSync();
   449 #endif
   450 };
   452 /**
   453  * A class of cacheable content list; cached on the combination of aRootNode + aFunc + aDataString
   454  */
   455 class nsCacheableFuncStringContentList;
   457 class MOZ_STACK_CLASS nsFuncStringCacheKey {
   458 public:
   459   nsFuncStringCacheKey(nsINode* aRootNode,
   460                        nsContentListMatchFunc aFunc,
   461                        const nsAString& aString) :
   462     mRootNode(aRootNode),
   463     mFunc(aFunc),
   464     mString(aString)
   465     {}
   467   uint32_t GetHash(void) const
   468   {
   469     uint32_t hash = mozilla::HashString(mString);
   470     return mozilla::AddToHash(hash, mRootNode, mFunc);
   471   }
   473 private:
   474   friend class nsCacheableFuncStringContentList;
   476   nsINode* const mRootNode;
   477   const nsContentListMatchFunc mFunc;
   478   const nsAString& mString;
   479 };
   481 // aDestroyFunc is allowed to be null
   482 // aDataAllocator must always return a non-null pointer
   483 class nsCacheableFuncStringContentList : public nsContentList {
   484 public:
   485   virtual ~nsCacheableFuncStringContentList();
   487   bool Equals(const nsFuncStringCacheKey* aKey) {
   488     return mRootNode == aKey->mRootNode && mFunc == aKey->mFunc &&
   489       mString == aKey->mString;
   490   }
   492 #ifdef DEBUG
   493   enum ContentListType {
   494     eNodeList,
   495     eHTMLCollection
   496   };
   497   ContentListType mType;
   498 #endif
   500 protected:
   501   nsCacheableFuncStringContentList(nsINode* aRootNode,
   502                                    nsContentListMatchFunc aFunc,
   503                                    nsContentListDestroyFunc aDestroyFunc,
   504                                    nsFuncStringContentListDataAllocator aDataAllocator,
   505                                    const nsAString& aString) :
   506     nsContentList(aRootNode, aFunc, aDestroyFunc, nullptr),
   507     mString(aString)
   508   {
   509     mData = (*aDataAllocator)(aRootNode, &mString);
   510     MOZ_ASSERT(mData);
   511   }
   513   virtual void RemoveFromCaches() MOZ_OVERRIDE {
   514     RemoveFromFuncStringHashtable();
   515   }
   516   void RemoveFromFuncStringHashtable();
   518   nsString mString;
   519 };
   521 class nsCacheableFuncStringNodeList
   522   : public nsCacheableFuncStringContentList
   523 {
   524 public:
   525   nsCacheableFuncStringNodeList(nsINode* aRootNode,
   526                                 nsContentListMatchFunc aFunc,
   527                                 nsContentListDestroyFunc aDestroyFunc,
   528                                 nsFuncStringContentListDataAllocator aDataAllocator,
   529                                 const nsAString& aString)
   530     : nsCacheableFuncStringContentList(aRootNode, aFunc, aDestroyFunc,
   531                                        aDataAllocator, aString)
   532   {
   533 #ifdef DEBUG
   534     mType = eNodeList;
   535 #endif
   536   }
   538   virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
   540 #ifdef DEBUG
   541   static const ContentListType sType;
   542 #endif
   543 };
   545 class nsCacheableFuncStringHTMLCollection
   546   : public nsCacheableFuncStringContentList
   547 {
   548 public:
   549   nsCacheableFuncStringHTMLCollection(nsINode* aRootNode,
   550                                       nsContentListMatchFunc aFunc,
   551                                       nsContentListDestroyFunc aDestroyFunc,
   552                                       nsFuncStringContentListDataAllocator aDataAllocator,
   553                                       const nsAString& aString)
   554     : nsCacheableFuncStringContentList(aRootNode, aFunc, aDestroyFunc,
   555                                        aDataAllocator, aString)
   556   {
   557 #ifdef DEBUG
   558     mType = eHTMLCollection;
   559 #endif
   560   }
   562   virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
   564 #ifdef DEBUG
   565   static const ContentListType sType;
   566 #endif
   567 };
   569 #endif // nsContentList_h___

mercurial