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  * A class for handing out nodeinfos and ensuring sharing of them as needed.
9  */
10 
11 #ifndef nsNodeInfoManager_h___
12 #define nsNodeInfoManager_h___
13 
14 #include "mozilla/Attributes.h"  // for final
15 #include "mozilla/dom/NodeInfo.h"
16 #include "mozilla/dom/DOMArena.h"
17 #include "mozilla/MruCache.h"
18 #include "nsCOMPtr.h"                      // for member
19 #include "nsCycleCollectionParticipant.h"  // for NS_DECL_CYCLE_*
20 #include "nsTHashMap.h"
21 #include "nsStringFwd.h"
22 
23 class nsAtom;
24 class nsIPrincipal;
25 class nsWindowSizes;
26 template <class T>
27 struct already_AddRefed;
28 
29 namespace mozilla {
30 namespace dom {
31 class Document;
32 }  // namespace dom
33 }  // namespace mozilla
34 
35 class nsNodeInfoManager final {
36  private:
37   ~nsNodeInfoManager();
38 
39  public:
40   nsNodeInfoManager();
41 
42   NS_DECL_CYCLE_COLLECTION_SKIPPABLE_NATIVE_CLASS(nsNodeInfoManager)
43 
44   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsNodeInfoManager)
45 
46   /**
47    * Initialize the nodeinfo manager with a document.
48    */
49   nsresult Init(mozilla::dom::Document*);
50 
51   /**
52    * Release the reference to the document, this will be called when
53    * the document is going away.
54    */
55   void DropDocumentReference();
56 
57   /**
58    * Methods for creating nodeinfo's from atoms and/or strings.
59    */
60   already_AddRefed<mozilla::dom::NodeInfo> GetNodeInfo(
61       nsAtom* aName, nsAtom* aPrefix, int32_t aNamespaceID, uint16_t aNodeType,
62       nsAtom* aExtraName = nullptr);
63   nsresult GetNodeInfo(const nsAString& aName, nsAtom* aPrefix,
64                        int32_t aNamespaceID, uint16_t aNodeType,
65                        mozilla::dom::NodeInfo** aNodeInfo);
66   nsresult GetNodeInfo(const nsAString& aName, nsAtom* aPrefix,
67                        const nsAString& aNamespaceURI, uint16_t aNodeType,
68                        mozilla::dom::NodeInfo** aNodeInfo);
69 
70   /**
71    * Returns the nodeinfo for text nodes. Can return null if OOM.
72    */
73   already_AddRefed<mozilla::dom::NodeInfo> GetTextNodeInfo();
74 
75   /**
76    * Returns the nodeinfo for comment nodes. Can return null if OOM.
77    */
78   already_AddRefed<mozilla::dom::NodeInfo> GetCommentNodeInfo();
79 
80   /**
81    * Returns the nodeinfo for the document node. Can return null if OOM.
82    */
83   already_AddRefed<mozilla::dom::NodeInfo> GetDocumentNodeInfo();
84 
85   /**
86    * Retrieve a pointer to the document that owns this node info
87    * manager.
88    */
GetDocument()89   mozilla::dom::Document* GetDocument() const { return mDocument; }
90 
91   /**
92    * Gets the principal of the document this nodeinfo manager belongs to.
93    */
DocumentPrincipal()94   nsIPrincipal* DocumentPrincipal() const {
95     NS_ASSERTION(mPrincipal, "How'd that happen?");
96     return mPrincipal;
97   }
98 
99   void RemoveNodeInfo(mozilla::dom::NodeInfo* aNodeInfo);
100 
101   /**
102    * Returns true if SVG nodes in this document have real SVG semantics.
103    */
SVGEnabled()104   bool SVGEnabled() {
105     return mSVGEnabled.valueOrFrom([this] { return InternalSVGEnabled(); });
106   }
107 
108   /**
109    * Returns true if MathML nodes in this document have real MathML semantics.
110    */
MathMLEnabled()111   bool MathMLEnabled() {
112     return mMathMLEnabled.valueOrFrom(
113         [this] { return InternalMathMLEnabled(); });
114   }
115 
GetArenaAllocator()116   mozilla::dom::DOMArena* GetArenaAllocator() { return mArena; }
117   void SetArenaAllocator(mozilla::dom::DOMArena* aArena);
118 
119   void* Allocate(size_t aSize);
120 
Free(void * aPtr)121   void Free(void* aPtr) { free(aPtr); }
122 
HasAllocated()123   bool HasAllocated() { return mHasAllocated; }
124 
125   void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
126 
127  protected:
128   friend class mozilla::dom::Document;
129   friend class nsXULPrototypeDocument;
130 
131   /**
132    * Sets the principal of the document this nodeinfo manager belongs to.
133    */
134   void SetDocumentPrincipal(nsIPrincipal* aPrincipal);
135 
136  private:
137   bool InternalSVGEnabled();
138   bool InternalMathMLEnabled();
139 
140   class NodeInfoInnerKey
141       : public nsPtrHashKey<mozilla::dom::NodeInfo::NodeInfoInner> {
142    public:
NodeInfoInnerKey(KeyTypePointer aKey)143     explicit NodeInfoInnerKey(KeyTypePointer aKey) : nsPtrHashKey(aKey) {}
144     NodeInfoInnerKey(NodeInfoInnerKey&&) = default;
145     ~NodeInfoInnerKey() = default;
KeyEquals(KeyTypePointer aKey)146     bool KeyEquals(KeyTypePointer aKey) const { return *mKey == *aKey; }
HashKey(KeyTypePointer aKey)147     static PLDHashNumber HashKey(KeyTypePointer aKey) { return aKey->Hash(); }
148   };
149 
150   struct NodeInfoCache
151       : public mozilla::MruCache<mozilla::dom::NodeInfo::NodeInfoInner,
152                                  mozilla::dom::NodeInfo*, NodeInfoCache> {
HashNodeInfoCache153     static mozilla::HashNumber Hash(
154         const mozilla::dom::NodeInfo::NodeInfoInner& aKey) {
155       return aKey.Hash();
156     }
MatchNodeInfoCache157     static bool Match(const mozilla::dom::NodeInfo::NodeInfoInner& aKey,
158                       const mozilla::dom::NodeInfo* aVal) {
159       return aKey == aVal->mInner;
160     }
161   };
162 
163   nsTHashMap<NodeInfoInnerKey, mozilla::dom::NodeInfo*> mNodeInfoHash;
164   mozilla::dom::Document* MOZ_NON_OWNING_REF mDocument;  // WEAK
165   uint32_t mNonDocumentNodeInfos;
166   nsCOMPtr<nsIPrincipal> mPrincipal;  // Never null after Init() succeeds.
167   nsCOMPtr<nsIPrincipal> mDefaultPrincipal;  // Never null after Init() succeeds
168   mozilla::dom::NodeInfo* MOZ_NON_OWNING_REF
169       mTextNodeInfo;  // WEAK to avoid circular ownership
170   mozilla::dom::NodeInfo* MOZ_NON_OWNING_REF
171       mCommentNodeInfo;  // WEAK to avoid circular ownership
172   mozilla::dom::NodeInfo* MOZ_NON_OWNING_REF
173       mDocumentNodeInfo;  // WEAK to avoid circular ownership
174   NodeInfoCache mRecentlyUsedNodeInfos;
175   mozilla::Maybe<bool> mSVGEnabled;     // Lazily initialized.
176   mozilla::Maybe<bool> mMathMLEnabled;  // Lazily initialized.
177 
178   // For dom_arena_allocator_enabled
179   RefPtr<mozilla::dom::DOMArena> mArena;
180   bool mHasAllocated = false;
181 };
182 
183 #endif /* nsNodeInfoManager_h___ */
184