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  * Class that represents a prefix/namespace/localName triple; a single
9  * nodeinfo is shared by all elements in a document that have that
10  * prefix, namespace, and localName.
11  *
12  * nsNodeInfoManagers are internal objects that manage a list of
13  * NodeInfos, every document object should hold a strong reference to
14  * a nsNodeInfoManager and every NodeInfo also holds a strong reference
15  * to their owning manager. When a NodeInfo is no longer used it will
16  * automatically remove itself from its owner manager, and when all
17  * NodeInfos have been removed from a nsNodeInfoManager and all external
18  * references are released the nsNodeInfoManager deletes itself.
19  */
20 
21 #ifndef mozilla_dom_NodeInfo_h___
22 #define mozilla_dom_NodeInfo_h___
23 
24 #include "nsCycleCollectionParticipant.h"
25 #include "mozilla/dom/NameSpaceConstants.h"
26 #include "nsString.h"
27 #include "mozilla/Attributes.h"
28 #include "mozilla/Maybe.h"
29 #include "nsAtom.h"
30 #include "nsHashKeys.h"
31 
32 class nsNodeInfoManager;
33 
34 namespace mozilla {
35 namespace dom {
36 
37 class Document;
38 
39 class NodeInfo final {
40  public:
41   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(NodeInfo)
42   NS_DECL_CYCLE_COLLECTION_SKIPPABLE_NATIVE_CLASS_WITH_CUSTOM_DELETE(NodeInfo)
43 
44   /*
45    * Get the name from this node as a string, this does not include the prefix.
46    *
47    * For the HTML element "<body>" this will return "body" and for the XML
48    * element "<html:body>" this will return "body".
49    */
50   void GetName(nsAString& aName) const;
51 
52   /*
53    * Get the name from this node as an atom, this does not include the prefix.
54    * This function never returns a null atom.
55    *
56    * For the HTML element "<body>" this will return the "body" atom and for
57    * the XML element "<html:body>" this will return the "body" atom.
58    */
NameAtom()59   nsAtom* NameAtom() const { return mInner.mName; }
60 
61   /*
62    * Get the qualified name from this node as a string, the qualified name
63    * includes the prefix, if one exists.
64    *
65    * For the HTML element "<body>" this will return "body" and for the XML
66    * element "<html:body>" this will return "html:body".
67    */
QualifiedName()68   const nsString& QualifiedName() const { return mQualifiedName; }
69 
70   /*
71    * Returns the node's nodeName as defined in DOM Core
72    */
NodeName()73   const nsString& NodeName() const { return mNodeName; }
74 
75   /*
76    * Returns the node's localName as defined in DOM Core
77    */
LocalName()78   const nsString& LocalName() const { return mLocalName; }
79 
80   /*
81    * Get the prefix from this node as a string.
82    *
83    * For the HTML element "<body>" this will return a null string and for
84    * the XML element "<html:body>" this will return the string "html".
85    */
86   void GetPrefix(nsAString& aPrefix) const;
87 
88   /*
89    * Get the prefix from this node as an atom.
90    *
91    * For the HTML element "<body>" this will return a null atom and for
92    * the XML element "<html:body>" this will return the "html" atom.
93    */
GetPrefixAtom()94   nsAtom* GetPrefixAtom() const { return mInner.mPrefix; }
95 
96   /*
97    * Get the namespace URI for a node, if the node has a namespace URI.
98    */
99   void GetNamespaceURI(nsAString& aNameSpaceURI) const;
100 
101   /*
102    * Get the namespace ID for a node if the node has a namespace, if not this
103    * returns kNameSpaceID_None.
104    */
NamespaceID()105   int32_t NamespaceID() const { return mInner.mNamespaceID; }
106 
107   /*
108    * Get the nodetype for the node. Returns the values specified in Node
109    * for Node.nodeType
110    */
NodeType()111   uint16_t NodeType() const { return mInner.mNodeType; }
112 
113   /*
114    * Get the extra name, used by PIs and DocTypes, for the node.
115    */
GetExtraName()116   nsAtom* GetExtraName() const { return mInner.mExtraName; }
117 
118   /**
119    * Get the owning node info manager. Only to be used inside Gecko, you can't
120    * really do anything with the pointer outside Gecko anyway.
121    */
NodeInfoManager()122   nsNodeInfoManager* NodeInfoManager() const { return mOwnerManager; }
123 
124   /*
125    * Utility functions that can be used to check if a nodeinfo holds a specific
126    * name, name and prefix, name and prefix and namespace ID, or just
127    * namespace ID.
128    */
129   inline bool Equals(NodeInfo* aNodeInfo) const;
130 
131   bool NameAndNamespaceEquals(NodeInfo* aNodeInfo) const;
132 
Equals(const nsAtom * aNameAtom)133   bool Equals(const nsAtom* aNameAtom) const {
134     return mInner.mName == aNameAtom;
135   }
136 
Equals(const nsAtom * aNameAtom,const nsAtom * aPrefixAtom)137   bool Equals(const nsAtom* aNameAtom, const nsAtom* aPrefixAtom) const {
138     return (mInner.mName == aNameAtom) && (mInner.mPrefix == aPrefixAtom);
139   }
140 
Equals(const nsAtom * aNameAtom,int32_t aNamespaceID)141   bool Equals(const nsAtom* aNameAtom, int32_t aNamespaceID) const {
142     return ((mInner.mName == aNameAtom) &&
143             (mInner.mNamespaceID == aNamespaceID));
144   }
145 
Equals(const nsAtom * aNameAtom,const nsAtom * aPrefixAtom,int32_t aNamespaceID)146   bool Equals(const nsAtom* aNameAtom, const nsAtom* aPrefixAtom,
147               int32_t aNamespaceID) const {
148     return ((mInner.mName == aNameAtom) && (mInner.mPrefix == aPrefixAtom) &&
149             (mInner.mNamespaceID == aNamespaceID));
150   }
151 
NamespaceEquals(int32_t aNamespaceID)152   bool NamespaceEquals(int32_t aNamespaceID) const {
153     return mInner.mNamespaceID == aNamespaceID;
154   }
155 
156   inline bool Equals(const nsAString& aName) const;
157 
158   inline bool Equals(const nsAString& aName, const nsAString& aPrefix) const;
159 
160   inline bool Equals(const nsAString& aName, int32_t aNamespaceID) const;
161 
162   inline bool Equals(const nsAString& aName, const nsAString& aPrefix,
163                      int32_t aNamespaceID) const;
164 
165   bool NamespaceEquals(const nsAString& aNamespaceURI) const;
166 
167   inline bool QualifiedNameEquals(const nsAtom* aNameAtom) const;
168 
QualifiedNameEquals(const nsAString & aQualifiedName)169   bool QualifiedNameEquals(const nsAString& aQualifiedName) const {
170     return mQualifiedName == aQualifiedName;
171   }
172 
173   /*
174    * Retrieve a pointer to the document that owns this node info.
175    */
GetDocument()176   Document* GetDocument() const { return mDocument; }
177 
178  private:
179   NodeInfo() = delete;
180   NodeInfo(const NodeInfo& aOther) = delete;
181 
182   // NodeInfo is only constructed by nsNodeInfoManager which is a friend class.
183   // aName and aOwnerManager may not be null.
184   NodeInfo(nsAtom* aName, nsAtom* aPrefix, int32_t aNamespaceID,
185            uint16_t aNodeType, nsAtom* aExtraName,
186            nsNodeInfoManager* aOwnerManager);
187 
188   ~NodeInfo();
189 
190  public:
191   bool CanSkip();
192 
193   /**
194    * This method gets called by the cycle collector when it's time to delete
195    * this object.
196    */
197   void DeleteCycleCollectable();
198 
199  protected:
200   /*
201    * NodeInfoInner is used for two things:
202    *
203    *   1. as a member in nsNodeInfo for holding the name, prefix and
204    *      namespace ID
205    *   2. as the hash key in the hash table in nsNodeInfoManager
206    *
207    * NodeInfoInner does not do any kind of reference counting,
208    * that's up to the user of this class. Since NodeInfoInner is
209    * typically used as a member of NodeInfo, the hash table doesn't
210    * need to delete the keys. When the value (NodeInfo) is deleted
211    * the key is automatically deleted.
212    */
213 
214   class NodeInfoInner {
215    public:
NodeInfoInner()216     NodeInfoInner()
217         : mName(nullptr),
218           mPrefix(nullptr),
219           mNamespaceID(kNameSpaceID_Unknown),
220           mNodeType(0),
221           mNameString(nullptr),
222           mExtraName(nullptr),
223           mHash() {}
NodeInfoInner(nsAtom * aName,nsAtom * aPrefix,int32_t aNamespaceID,uint16_t aNodeType,nsAtom * aExtraName)224     NodeInfoInner(nsAtom* aName, nsAtom* aPrefix, int32_t aNamespaceID,
225                   uint16_t aNodeType, nsAtom* aExtraName)
226         : mName(aName),
227           mPrefix(aPrefix),
228           mNamespaceID(aNamespaceID),
229           mNodeType(aNodeType),
230           mNameString(nullptr),
231           mExtraName(aExtraName),
232           mHash() {}
NodeInfoInner(const nsAString & aTmpName,nsAtom * aPrefix,int32_t aNamespaceID,uint16_t aNodeType)233     NodeInfoInner(const nsAString& aTmpName, nsAtom* aPrefix,
234                   int32_t aNamespaceID, uint16_t aNodeType)
235         : mName(nullptr),
236           mPrefix(aPrefix),
237           mNamespaceID(aNamespaceID),
238           mNodeType(aNodeType),
239           mNameString(&aTmpName),
240           mExtraName(nullptr),
241           mHash() {}
242 
243     bool operator==(const NodeInfoInner& aOther) const {
244       if (mPrefix != aOther.mPrefix || mNamespaceID != aOther.mNamespaceID ||
245           mNodeType != aOther.mNodeType || mExtraName != aOther.mExtraName) {
246         return false;
247       }
248 
249       if (mName) {
250         if (aOther.mName) {
251           return mName == aOther.mName;
252         }
253         return mName->Equals(*(aOther.mNameString));
254       }
255 
256       if (aOther.mName) {
257         return aOther.mName->Equals(*(mNameString));
258       }
259 
260       return mNameString->Equals(*(aOther.mNameString));
261     }
262 
Hash()263     uint32_t Hash() const {
264       if (!mHash) {
265         mHash.emplace(mName ? mName->hash()
266                             : mozilla::HashString(*mNameString));
267       }
268       return mHash.value();
269     }
270 
271     nsAtom* const MOZ_OWNING_REF mName;
272     nsAtom* MOZ_OWNING_REF mPrefix;
273     int32_t mNamespaceID;
274     uint16_t mNodeType;  // As defined by Node.nodeType
275     const nsAString* const mNameString;
276     nsAtom* MOZ_OWNING_REF mExtraName;  // Only used by PIs and DocTypes
277     mutable mozilla::Maybe<const uint32_t> mHash;
278   };
279 
280   // nsNodeInfoManager needs to pass mInner to the hash table.
281   friend class ::nsNodeInfoManager;
282 
283   // This is a non-owning reference, but it's safe since it's set to nullptr
284   // by nsNodeInfoManager::DropDocumentReference when the document is destroyed.
285   Document* MOZ_NON_OWNING_REF mDocument;  // Cache of mOwnerManager->mDocument
286 
287   NodeInfoInner mInner;
288 
289   RefPtr<nsNodeInfoManager> mOwnerManager;
290 
291   /*
292    * Members for various functions of mName+mPrefix that we can be
293    * asked to compute.
294    */
295 
296   // Qualified name
297   nsString mQualifiedName;
298 
299   // nodeName for the node.
300   nsString mNodeName;
301 
302   // localName for the node. This is either equal to mInner.mName, or a
303   // void string, depending on mInner.mNodeType.
304   nsString mLocalName;
305 };
306 
307 }  // namespace dom
308 }  // namespace mozilla
309 
310 #endif /* mozilla_dom_NodeInfo_h___ */
311