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