1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=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/. */
7 #ifndef mozilla_a11y_DocAccessibleParent_h
8 #define mozilla_a11y_DocAccessibleParent_h
10 #include "nsAccessibilityService.h"
11 #include "mozilla/a11y/PDocAccessibleParent.h"
12 #include "mozilla/a11y/ProxyAccessible.h"
13 #include "mozilla/Tuple.h"
14 #include "nsClassHashtable.h"
15 #include "nsHashKeys.h"
16 #include "nsISupportsImpl.h"
21 class xpcAccessibleGeneric
;
24 class DocAccessiblePlatformExtParent
;
28 * These objects live in the main process and comunicate with and represent
29 * an accessible document in a content process.
31 class DocAccessibleParent
: public ProxyAccessible
,
32 public PDocAccessibleParent
{
34 NS_INLINE_DECL_REFCOUNTING(DocAccessibleParent
);
37 : ProxyAccessible(this),
38 mParentDoc(kNoParentDoc
),
40 mEmulatedWindowHandle(nullptr),
41 #endif // defined(XP_WIN)
43 mTopLevelInContentProcess(false),
47 MOZ_ASSERT(!LiveDocs().Get(mActorID
));
48 LiveDocs().Put(mActorID
, this);
52 * Set this as a top level document; i.e. it is not embedded by another remote
53 * document. This also means it is a top level document in its content
55 * Tab documents are top level documents.
59 mTopLevelInContentProcess
= true;
61 bool IsTopLevel() const { return mTopLevel
; }
64 * Set this as a top level document in its content process.
65 * Note that this could be an out-of-process iframe embedded by a remote
66 * embedder document. In that case, IsToplevel() will return false, but
67 * IsTopLevelInContentProcess() will return true.
69 void SetTopLevelInContentProcess() { mTopLevelInContentProcess
= true; }
70 bool IsTopLevelInContentProcess() const { return mTopLevelInContentProcess
; }
72 bool IsShutdown() const { return mShutdown
; }
75 * Mark this actor as shutdown without doing any cleanup. This should only
76 * be called on actors that have just been initialized, so probably only from
77 * RecvPDocAccessibleConstructor.
79 void MarkAsShutdown() {
80 MOZ_ASSERT(mChildDocs
.IsEmpty());
81 MOZ_ASSERT(mAccessibles
.Count() == 0);
86 * Called when a message from a document in a child process notifies the main
87 * process it is firing an event.
89 virtual mozilla::ipc::IPCResult
RecvEvent(const uint64_t& aID
,
90 const uint32_t& aType
) override
;
92 virtual mozilla::ipc::IPCResult
RecvShowEvent(const ShowEventData
& aData
,
93 const bool& aFromUser
) override
;
94 virtual mozilla::ipc::IPCResult
RecvHideEvent(const uint64_t& aRootID
,
95 const bool& aFromUser
) override
;
96 mozilla::ipc::IPCResult
RecvStateChangeEvent(const uint64_t& aID
,
97 const uint64_t& aState
,
98 const bool& aEnabled
) final
;
100 mozilla::ipc::IPCResult
RecvCaretMoveEvent(
103 const LayoutDeviceIntRect
& aCaretRect
,
105 const int32_t& aOffset
, const bool& aIsSelectionCollapsed
) final
;
107 virtual mozilla::ipc::IPCResult
RecvTextChangeEvent(
108 const uint64_t& aID
, const nsString
& aStr
, const int32_t& aStart
,
109 const uint32_t& aLen
, const bool& aIsInsert
,
110 const bool& aFromUser
) override
;
113 virtual mozilla::ipc::IPCResult
RecvSyncTextChangeEvent(
114 const uint64_t& aID
, const nsString
& aStr
, const int32_t& aStart
,
115 const uint32_t& aLen
, const bool& aIsInsert
,
116 const bool& aFromUser
) override
;
118 virtual mozilla::ipc::IPCResult
RecvFocusEvent(
119 const uint64_t& aID
, const LayoutDeviceIntRect
& aCaretRect
) override
;
120 #endif // defined(XP_WIN)
122 virtual mozilla::ipc::IPCResult
RecvSelectionEvent(
123 const uint64_t& aID
, const uint64_t& aWidgetID
,
124 const uint32_t& aType
) override
;
126 MOZ_CAN_RUN_SCRIPT_BOUNDARY
127 virtual mozilla::ipc::IPCResult
RecvVirtualCursorChangeEvent(
128 const uint64_t& aID
, const uint64_t& aOldPositionID
,
129 const int32_t& aOldStartOffset
, const int32_t& aOldEndOffset
,
130 const uint64_t& aNewPositionID
, const int32_t& aNewStartOffset
,
131 const int32_t& aNewEndOffset
, const int16_t& aReason
,
132 const int16_t& aBoundaryType
, const bool& aFromUser
) override
;
134 virtual mozilla::ipc::IPCResult
RecvScrollingEvent(
135 const uint64_t& aID
, const uint64_t& aType
, const uint32_t& aScrollX
,
136 const uint32_t& aScrollY
, const uint32_t& aMaxScrollX
,
137 const uint32_t& aMaxScrollY
) override
;
140 virtual mozilla::ipc::IPCResult
RecvAnnouncementEvent(
141 const uint64_t& aID
, const nsString
& aAnnouncement
,
142 const uint16_t& aPriority
) override
;
144 virtual mozilla::ipc::IPCResult
RecvTextSelectionChangeEvent(
145 const uint64_t& aID
, nsTArray
<TextRangeData
>&& aSelection
) override
;
148 mozilla::ipc::IPCResult
RecvRoleChangedEvent(const a11y::role
& aRole
) final
;
150 virtual mozilla::ipc::IPCResult
RecvBindChildDoc(
151 PDocAccessibleParent
* aChildDoc
, const uint64_t& aID
) override
;
154 if (DocAccessibleParent
* parent
= ParentDoc()) {
155 parent
->RemoveChildDoc(this);
161 virtual mozilla::ipc::IPCResult
RecvShutdown() override
;
163 virtual void ActorDestroy(ActorDestroyReason aWhy
) override
{
164 MOZ_ASSERT(CheckDocTree());
165 if (!mShutdown
) Destroy();
169 * Return the main processes representation of the parent document (if any)
170 * of the document this object represents.
172 DocAccessibleParent
* ParentDoc() const;
173 static const uint64_t kNoParentDoc
= UINT64_MAX
;
176 * Called when a document in a content process notifies the main process of a
177 * new child document.
179 ipc::IPCResult
AddChildDoc(DocAccessibleParent
* aChildDoc
, uint64_t aParentID
,
180 bool aCreating
= true);
183 * Called when the document in the content process this object represents
184 * notifies the main process a child document has been removed.
186 void RemoveChildDoc(DocAccessibleParent
* aChildDoc
) {
187 ProxyAccessible
* parent
= aChildDoc
->Parent();
190 aChildDoc
->Parent()->ClearChildDoc(aChildDoc
);
192 DebugOnly
<bool> result
= mChildDocs
.RemoveElement(aChildDoc
->mActorID
);
193 aChildDoc
->mParentDoc
= kNoParentDoc
;
197 void RemoveAccessible(ProxyAccessible
* aAccessible
) {
198 MOZ_DIAGNOSTIC_ASSERT(mAccessibles
.GetEntry(aAccessible
->ID()));
199 mAccessibles
.RemoveEntry(aAccessible
->ID());
203 * Return the accessible for given id.
205 ProxyAccessible
* GetAccessible(uintptr_t aID
) {
206 if (!aID
) return this;
208 ProxyEntry
* e
= mAccessibles
.GetEntry(aID
);
209 return e
? e
->mProxy
: nullptr;
212 const ProxyAccessible
* GetAccessible(uintptr_t aID
) const {
213 return const_cast<DocAccessibleParent
*>(this)->GetAccessible(aID
);
216 size_t ChildDocCount() const { return mChildDocs
.Length(); }
217 const DocAccessibleParent
* ChildDocAt(size_t aIdx
) const {
218 return const_cast<DocAccessibleParent
*>(this)->ChildDocAt(aIdx
);
220 DocAccessibleParent
* ChildDocAt(size_t aIdx
) {
221 return LiveDocs().Get(mChildDocs
[aIdx
]);
225 void MaybeInitWindowEmulation();
228 * Note that an OuterDocAccessible can be created before the
229 * DocAccessibleParent or vice versa. Therefore, this must be conditionally
230 * called when either of these is created.
231 * @param aOuterDoc The OuterDocAccessible to be returned as the parent of
232 * this document. Only GetNativeInterface() is called on this, so it
233 * may be a ProxyAccessibleWrap or similar.
235 void SendParentCOMProxy(Accessible
* aOuterDoc
);
237 virtual mozilla::ipc::IPCResult
RecvGetWindowedPluginIAccessible(
238 const WindowsHandle
& aHwnd
, IAccessibleHolder
* aPluginCOMProxy
) override
;
241 * Set emulated native window handle for a document.
242 * @param aWindowHandle emulated native window handle
244 void SetEmulatedWindowHandle(HWND aWindowHandle
);
245 HWND
GetEmulatedWindowHandle() const { return mEmulatedWindowHandle
; }
249 virtual mozilla::ipc::IPCResult
RecvBatch(
250 const uint64_t& aBatchType
, nsTArray
<BatchData
>&& aData
) override
;
252 virtual bool DeallocPDocAccessiblePlatformExtParent(
253 PDocAccessiblePlatformExtParent
* aActor
) override
;
255 virtual PDocAccessiblePlatformExtParent
*
256 AllocPDocAccessiblePlatformExtParent() override
;
258 DocAccessiblePlatformExtParent
* GetPlatformExtension();
262 * If this is an iframe document rendered in a different process to its
263 * embedder, return the DocAccessibleParent and id for the embedder
264 * accessible. Otherwise, return null and 0.
266 Tuple
<DocAccessibleParent
*, uint64_t> GetRemoteEmbedder();
269 ~DocAccessibleParent() {
270 LiveDocs().Remove(mActorID
);
271 MOZ_ASSERT(mChildDocs
.Length() == 0);
272 MOZ_ASSERT(!ParentDoc());
275 class ProxyEntry
: public PLDHashEntryHdr
{
277 explicit ProxyEntry(const void*) : mProxy(nullptr) {}
278 ProxyEntry(ProxyEntry
&& aOther
) : mProxy(aOther
.mProxy
) {
279 aOther
.mProxy
= nullptr;
281 ~ProxyEntry() { delete mProxy
; }
283 typedef uint64_t KeyType
;
284 typedef const void* KeyTypePointer
;
286 bool KeyEquals(const void* aKey
) const {
287 return mProxy
->ID() == (uint64_t)aKey
;
290 static const void* KeyToPointer(uint64_t aKey
) { return (void*)aKey
; }
292 static PLDHashNumber
HashKey(const void* aKey
) { return (uint64_t)aKey
; }
294 enum { ALLOW_MEMMOVE
= true };
296 ProxyAccessible
* mProxy
;
299 uint32_t AddSubtree(ProxyAccessible
* aParent
,
300 const nsTArray
<AccessibleData
>& aNewTree
, uint32_t aIdx
,
301 uint32_t aIdxInParent
);
302 [[nodiscard
]] bool CheckDocTree() const;
303 xpcAccessibleGeneric
* GetXPCAccessible(ProxyAccessible
* aProxy
);
305 nsTArray
<uint64_t> mChildDocs
;
309 // The handle associated with the emulated window that contains this document
310 HWND mEmulatedWindowHandle
;
312 # if defined(MOZ_SANDBOX)
313 mscom::PreservedStreamPtr mParentProxyStream
;
314 mscom::PreservedStreamPtr mDocProxyStream
;
315 mscom::PreservedStreamPtr mTopLevelDocProxyStream
;
316 # endif // defined(MOZ_SANDBOX)
317 #endif // defined(XP_WIN)
320 * Conceptually this is a map from IDs to proxies, but we store the ID in the
321 * proxy object so we can't use a real map.
323 nsTHashtable
<ProxyEntry
> mAccessibles
;
326 bool mTopLevelInContentProcess
;
329 struct PendingChildDoc
{
330 PendingChildDoc(DocAccessibleParent
* aChildDoc
, uint64_t aParentID
)
331 : mChildDoc(aChildDoc
), mParentID(aParentID
) {}
332 RefPtr
<DocAccessibleParent
> mChildDoc
;
335 // We use nsTArray because there will be very few entries.
336 nsTArray
<PendingChildDoc
> mPendingChildDocs
;
338 static uint64_t sMaxDocID
;
339 static nsDataHashtable
<nsUint64HashKey
, DocAccessibleParent
*>& LiveDocs() {
340 static nsDataHashtable
<nsUint64HashKey
, DocAccessibleParent
*> sLiveDocs
;
346 } // namespace mozilla