Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / dom / base / IdentifierMapEntry.h
blob27434e932daa392d9a44411ae8b881a3607b6ce8
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/. */
7 /*
8 * Entry for the Document or ShadowRoot's identifier map.
9 */
11 #ifndef mozilla_IdentifierMapEntry_h
12 #define mozilla_IdentifierMapEntry_h
14 #include <utility>
16 #include "PLDHashTable.h"
17 #include "mozilla/MemoryReporting.h"
18 #include "mozilla/UniquePtr.h"
19 #include "mozilla/dom/TreeOrderedArray.h"
20 #include "nsAtom.h"
21 #include "nsCOMPtr.h"
22 #include "nsContentList.h"
23 #include "nsHashKeys.h"
24 #include "nsTArray.h"
25 #include "nsTHashtable.h"
27 class nsIContent;
28 class nsINode;
30 namespace mozilla {
31 namespace dom {
32 class Document;
33 class Element;
34 } // namespace dom
36 /**
37 * Right now our identifier map entries contain information for 'name'
38 * and 'id' mappings of a given string. This is so that
39 * nsHTMLDocument::ResolveName only has to do one hash lookup instead
40 * of two. It's not clear whether this still matters for performance.
42 * We also store the document.all result list here. This is mainly so that
43 * when all elements with the given ID are removed and we remove
44 * the ID's IdentifierMapEntry, the document.all result is released too.
45 * Perhaps the document.all results should have their own hashtable
46 * in nsHTMLDocument.
48 class IdentifierMapEntry : public PLDHashEntryHdr {
49 typedef dom::Document Document;
50 typedef dom::Element Element;
52 /**
53 * @see Document::IDTargetObserver, this is just here to avoid include hell.
55 typedef bool (*IDTargetObserver)(Element* aOldElement, Element* aNewelement,
56 void* aData);
58 public:
59 // We use DependentAtomOrString as our external key interface. This allows
60 // consumers to use an nsAString, for example, without forcing a copy.
61 struct DependentAtomOrString final {
62 MOZ_IMPLICIT DependentAtomOrString(nsAtom* aAtom)
63 : mAtom(aAtom), mString(nullptr) {}
64 MOZ_IMPLICIT DependentAtomOrString(const nsAString& aString)
65 : mAtom(nullptr), mString(&aString) {}
66 DependentAtomOrString(const DependentAtomOrString& aOther) = default;
68 nsAtom* mAtom;
69 const nsAString* mString;
72 typedef const DependentAtomOrString& KeyType;
73 typedef const DependentAtomOrString* KeyTypePointer;
75 explicit IdentifierMapEntry(const DependentAtomOrString* aKey);
76 IdentifierMapEntry(IdentifierMapEntry&& aOther) = default;
77 ~IdentifierMapEntry() = default;
79 nsString GetKeyAsString() const {
80 if (mKey.mAtom) {
81 return nsAtomString(mKey.mAtom);
84 return mKey.mString;
87 bool KeyEquals(const KeyTypePointer aOtherKey) const {
88 if (mKey.mAtom) {
89 if (aOtherKey->mAtom) {
90 return mKey.mAtom == aOtherKey->mAtom;
93 return mKey.mAtom->Equals(*aOtherKey->mString);
96 if (aOtherKey->mAtom) {
97 return aOtherKey->mAtom->Equals(mKey.mString);
100 return mKey.mString.Equals(*aOtherKey->mString);
103 static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
105 static PLDHashNumber HashKey(const KeyTypePointer aKey) {
106 return aKey->mAtom ? aKey->mAtom->hash() : HashString(*aKey->mString);
109 enum { ALLOW_MEMMOVE = false };
111 void AddNameElement(nsINode* aDocument, Element* aElement);
112 void RemoveNameElement(Element* aElement);
113 bool IsEmpty();
114 nsBaseContentList* GetNameContentList() { return mNameContentList; }
115 bool HasNameElement() const;
118 * Returns the element if we know the element associated with this
119 * id. Otherwise returns null.
121 Element* GetIdElement() const { return mIdContentList->SafeElementAt(0); }
124 * Returns the list of all elements associated with this id.
126 const nsTArray<Element*>& GetIdElements() const { return mIdContentList; }
129 * If this entry has a non-null image element set (using SetImageElement),
130 * the image element will be returned, otherwise the same as GetIdElement().
132 Element* GetImageIdElement() {
133 return mImageElement ? mImageElement.get() : GetIdElement();
137 * This can fire ID change callbacks.
139 void AddIdElement(Element* aElement);
141 * This can fire ID change callbacks.
143 void RemoveIdElement(Element* aElement);
145 * Set the image element override for this ID. This will be returned by
146 * GetIdElement(true) if non-null.
148 void SetImageElement(Element* aElement);
149 bool HasIdElementExposedAsHTMLDocumentProperty() const;
151 bool HasContentChangeCallback() { return mChangeCallbacks != nullptr; }
152 void AddContentChangeCallback(IDTargetObserver aCallback, void* aData,
153 bool aForImage);
154 void RemoveContentChangeCallback(IDTargetObserver aCallback, void* aData,
155 bool aForImage);
158 * Remove all elements and notify change listeners.
160 void ClearAndNotify();
162 void Traverse(nsCycleCollectionTraversalCallback* aCallback);
164 struct ChangeCallback {
165 IDTargetObserver mCallback;
166 void* mData;
167 bool mForImage;
170 struct ChangeCallbackEntry : public PLDHashEntryHdr {
171 typedef const ChangeCallback KeyType;
172 typedef const ChangeCallback* KeyTypePointer;
174 explicit ChangeCallbackEntry(const ChangeCallback* aKey) : mKey(*aKey) {}
175 ChangeCallbackEntry(ChangeCallbackEntry&& aOther)
176 : PLDHashEntryHdr(std::move(aOther)), mKey(std::move(aOther.mKey)) {}
178 KeyType GetKey() const { return mKey; }
179 bool KeyEquals(KeyTypePointer aKey) const {
180 return aKey->mCallback == mKey.mCallback && aKey->mData == mKey.mData &&
181 aKey->mForImage == mKey.mForImage;
184 static KeyTypePointer KeyToPointer(KeyType& aKey) { return &aKey; }
185 static PLDHashNumber HashKey(KeyTypePointer aKey) {
186 return HashGeneric(aKey->mCallback, aKey->mData);
188 enum { ALLOW_MEMMOVE = true };
190 ChangeCallback mKey;
193 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
195 private:
196 // We use an OwningAtomOrString as our internal key storage. It needs to own
197 // the key string, whether in atom or string form.
198 struct OwningAtomOrString final {
199 OwningAtomOrString(const OwningAtomOrString& aOther) = delete;
200 OwningAtomOrString(OwningAtomOrString&& aOther) = default;
202 explicit OwningAtomOrString(const DependentAtomOrString& aOther)
203 // aOther may have a null mString, so jump through a bit of a hoop in
204 // that case. I wish there were a way to just default-initialize
205 // mString in that situation... We could also make mString not const
206 // and only assign to it if aOther.mString is not null, but having it be
207 // const is nice.
208 : mAtom(aOther.mAtom),
209 mString(aOther.mString ? *aOther.mString : u""_ns) {}
211 RefPtr<nsAtom> mAtom;
212 nsString mString;
215 IdentifierMapEntry(const IdentifierMapEntry& aOther) = delete;
216 IdentifierMapEntry& operator=(const IdentifierMapEntry& aOther) = delete;
218 void FireChangeCallbacks(Element* aOldElement, Element* aNewElement,
219 bool aImageOnly = false);
221 OwningAtomOrString mKey;
222 dom::TreeOrderedArray<Element*> mIdContentList;
223 RefPtr<nsBaseContentList> mNameContentList;
224 UniquePtr<nsTHashtable<ChangeCallbackEntry> > mChangeCallbacks;
225 RefPtr<Element> mImageElement;
228 } // namespace mozilla
230 #endif // #ifndef mozilla_IdentifierMapEntry_h