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/. */
8 * Entry for the Document or ShadowRoot's identifier map.
11 #ifndef mozilla_IdentifierMapEntry_h
12 #define mozilla_IdentifierMapEntry_h
16 #include "PLDHashTable.h"
17 #include "mozilla/MemoryReporting.h"
18 #include "mozilla/UniquePtr.h"
19 #include "mozilla/dom/TreeOrderedArray.h"
22 #include "nsContentList.h"
23 #include "nsHashKeys.h"
25 #include "nsTHashtable.h"
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
48 class IdentifierMapEntry
: public PLDHashEntryHdr
{
49 typedef dom::Document Document
;
50 typedef dom::Element Element
;
53 * @see Document::IDTargetObserver, this is just here to avoid include hell.
55 typedef bool (*IDTargetObserver
)(Element
* aOldElement
, Element
* aNewelement
,
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;
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 {
81 return nsAtomString(mKey
.mAtom
);
87 bool KeyEquals(const KeyTypePointer aOtherKey
) const {
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
);
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
,
154 void RemoveContentChangeCallback(IDTargetObserver aCallback
, void* aData
,
158 * Remove all elements and notify change listeners.
160 void ClearAndNotify();
162 void Traverse(nsCycleCollectionTraversalCallback
* aCallback
);
164 struct ChangeCallback
{
165 IDTargetObserver mCallback
;
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 };
193 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf
) const;
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
208 : mAtom(aOther
.mAtom
),
209 mString(aOther
.mString
? *aOther
.mString
: u
""_ns
) {}
211 RefPtr
<nsAtom
> mAtom
;
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