1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 #ifndef mozilla_a11_DocManager_h_
6 #define mozilla_a11_DocManager_h_
7 
8 #include "mozilla/ClearOnShutdown.h"
9 #include "mozilla/PresShell.h"
10 #include "mozilla/dom/Document.h"
11 #include "nsIDOMEventListener.h"
12 #include "nsRefPtrHashtable.h"
13 #include "nsIWebProgressListener.h"
14 #include "nsWeakReference.h"
15 #include "mozilla/StaticPtr.h"
16 
17 namespace mozilla {
18 namespace a11y {
19 
20 class Accessible;
21 class DocAccessible;
22 class xpcAccessibleDocument;
23 class DocAccessibleParent;
24 
25 /**
26  * Manage the document accessible life cycle.
27  */
28 class DocManager : public nsIWebProgressListener,
29                    public nsIDOMEventListener,
30                    public nsSupportsWeakReference {
31  public:
32   NS_DECL_THREADSAFE_ISUPPORTS
33   NS_DECL_NSIWEBPROGRESSLISTENER
34   NS_DECL_NSIDOMEVENTLISTENER
35 
36   /**
37    * Return document accessible for the given DOM node.
38    */
39   DocAccessible* GetDocAccessible(dom::Document* aDocument);
40 
41   /**
42    * Return document accessible for the given presshell.
43    */
GetDocAccessible(const PresShell * aPresShell)44   DocAccessible* GetDocAccessible(const PresShell* aPresShell) {
45     if (!aPresShell) {
46       return nullptr;
47     }
48 
49     DocAccessible* doc = aPresShell->GetDocAccessible();
50     if (doc) {
51       return doc;
52     }
53 
54     return GetDocAccessible(aPresShell->GetDocument());
55   }
56 
57   /**
58    * Search through all document accessibles for an accessible with the given
59    * unique id.
60    */
61   Accessible* FindAccessibleInCache(nsINode* aNode) const;
62 
63   /**
64    * Called by document accessible when it gets shutdown.
65    */
66   void NotifyOfDocumentShutdown(DocAccessible* aDocument,
67                                 dom::Document* aDOMDocument);
68 
69   void RemoveFromXPCDocumentCache(DocAccessible* aDocument);
70 
71   /**
72    * Return XPCOM accessible document.
73    */
74   xpcAccessibleDocument* GetXPCDocument(DocAccessible* aDocument);
GetCachedXPCDocument(DocAccessible * aDocument)75   xpcAccessibleDocument* GetCachedXPCDocument(DocAccessible* aDocument) const {
76     return mXPCDocumentCache.GetWeak(aDocument);
77   }
78 
79   /*
80    * Notification that a top level document in a content process has gone away.
81    */
RemoteDocShutdown(DocAccessibleParent * aDoc)82   static void RemoteDocShutdown(DocAccessibleParent* aDoc) {
83     DebugOnly<bool> result = sRemoteDocuments->RemoveElement(aDoc);
84     MOZ_ASSERT(result, "Why didn't we find the document!");
85   }
86 
87   /*
88    * Notify of a new top level document in a content process.
89    */
90   static void RemoteDocAdded(DocAccessibleParent* aDoc);
91 
TopLevelRemoteDocs()92   static const nsTArray<DocAccessibleParent*>* TopLevelRemoteDocs() {
93     return sRemoteDocuments;
94   }
95 
96   /**
97    * Remove the xpc document for a remote document if there is one.
98    */
99   static void NotifyOfRemoteDocShutdown(DocAccessibleParent* adoc);
100 
101   static void RemoveFromRemoteXPCDocumentCache(DocAccessibleParent* aDoc);
102 
103   /**
104    * Get a XPC document for a remote document.
105    */
106   static xpcAccessibleDocument* GetXPCDocument(DocAccessibleParent* aDoc);
GetCachedXPCDocument(const DocAccessibleParent * aDoc)107   static xpcAccessibleDocument* GetCachedXPCDocument(
108       const DocAccessibleParent* aDoc) {
109     return sRemoteXPCDocumentCache ? sRemoteXPCDocumentCache->GetWeak(aDoc)
110                                    : nullptr;
111   }
112 
113 #ifdef DEBUG
114   bool IsProcessingRefreshDriverNotification() const;
115 #endif
116 
117  protected:
118   DocManager();
119   virtual ~DocManager() = default;
120 
121   /**
122    * Initialize the manager.
123    */
124   bool Init();
125 
126   /**
127    * Shutdown the manager.
128    */
129   void Shutdown();
130 
HasXPCDocuments()131   bool HasXPCDocuments() {
132     return mXPCDocumentCache.Count() > 0 ||
133            (sRemoteXPCDocumentCache && sRemoteXPCDocumentCache->Count() > 0);
134   }
135 
136  private:
137   DocManager(const DocManager&);
138   DocManager& operator=(const DocManager&);
139 
140  private:
141   /**
142    * Create an accessible document if it was't created and fire accessibility
143    * events if needed.
144    *
145    * @param  aDocument       [in] loaded DOM document
146    * @param  aLoadEventType  [in] specifies the event type to fire load event,
147    *                           if 0 then no event is fired
148    */
149   void HandleDOMDocumentLoad(dom::Document* aDocument, uint32_t aLoadEventType);
150 
151   /**
152    * Add/remove 'pagehide' and 'DOMContentLoaded' event listeners.
153    */
154   void AddListeners(dom::Document* aDocument, bool aAddPageShowListener);
155   void RemoveListeners(dom::Document* aDocument);
156 
157   /**
158    * Create document or root accessible.
159    */
160   DocAccessible* CreateDocOrRootAccessible(dom::Document* aDocument);
161 
162   /**
163    * Clear the cache and shutdown the document accessibles.
164    */
165   void ClearDocCache();
166 
167   typedef nsRefPtrHashtable<nsPtrHashKey<const dom::Document>, DocAccessible>
168       DocAccessibleHashtable;
169   DocAccessibleHashtable mDocAccessibleCache;
170 
171   typedef nsRefPtrHashtable<nsPtrHashKey<const DocAccessible>,
172                             xpcAccessibleDocument>
173       XPCDocumentHashtable;
174   XPCDocumentHashtable mXPCDocumentCache;
175   static nsRefPtrHashtable<nsPtrHashKey<const DocAccessibleParent>,
176                            xpcAccessibleDocument>* sRemoteXPCDocumentCache;
177 
178   /*
179    * The list of remote top level documents.
180    */
181   static StaticAutoPtr<nsTArray<DocAccessibleParent*>> sRemoteDocuments;
182 };
183 
184 /**
185  * Return the existing document accessible for the document if any.
186  * Note this returns the doc accessible for the primary pres shell if there is
187  * more than one.
188  */
GetExistingDocAccessible(const dom::Document * aDocument)189 inline DocAccessible* GetExistingDocAccessible(const dom::Document* aDocument) {
190   PresShell* presShell = aDocument->GetPresShell();
191   return presShell ? presShell->GetDocAccessible() : nullptr;
192 }
193 
194 }  // namespace a11y
195 }  // namespace mozilla
196 
197 #endif  // mozilla_a11_DocManager_h_
198