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