diff --git a/accessible/ipc/DocAccessibleParent.h b/accessible/ipc/DocAccessibleParent.h index 0765e27fcade..e35002bb8bae 100644 --- a/accessible/ipc/DocAccessibleParent.h +++ b/accessible/ipc/DocAccessibleParent.h @@ -36,6 +36,7 @@ class DocAccessibleParent : public ProxyAccessible, mEmulatedWindowHandle(nullptr), #endif // defined(XP_WIN) mTopLevel(false), + mTopLevelInContentProcess(false), mShutdown(false) { sMaxDocID++; mActorID = sMaxDocID; @@ -43,9 +44,27 @@ class DocAccessibleParent : public ProxyAccessible, LiveDocs().Put(mActorID, this); } - void SetTopLevel() { mTopLevel = true; } + /** + * Set this as a top level document; i.e. it is not embedded by another remote + * document. This also means it is a top level document in its content + * process. + * Tab documents are top level documents. + */ + void SetTopLevel() { + mTopLevel = true; + mTopLevelInContentProcess = true; + } bool IsTopLevel() const { return mTopLevel; } + /** + * Set this as a top level document in its content process. + * Note that this could be an out-of-process iframe embedded by a remote + * embedder document. In that case, IsToplevel() will return false, but + * IsTopLevelInContentProcess() will return true. + */ + void SetTopLevelInContentProcess() { mTopLevelInContentProcess = true; } + bool IsTopLevelInContentProcess() const { return mTopLevelInContentProcess; } + bool IsShutdown() const { return mShutdown; } /** @@ -279,6 +298,7 @@ class DocAccessibleParent : public ProxyAccessible, nsTHashtable mAccessibles; uint64_t mActorID; bool mTopLevel; + bool mTopLevelInContentProcess; bool mShutdown; static uint64_t sMaxDocID; diff --git a/dom/ipc/BrowserParent.cpp b/dom/ipc/BrowserParent.cpp index e6ceff4290d5..cc63fda52294 100644 --- a/dom/ipc/BrowserParent.cpp +++ b/dom/ipc/BrowserParent.cpp @@ -409,7 +409,11 @@ a11y::DocAccessibleParent* BrowserParent::GetTopLevelDocAccessible() const { ManagedPDocAccessibleParent(); for (auto iter = docs.ConstIter(); !iter.Done(); iter.Next()) { auto doc = static_cast(iter.Get()->GetKey()); - if (doc->IsTopLevel()) { + // We want the document for this BrowserParent even if it's for an + // embedded out-of-process iframe. Therefore, we use + // IsTopLevelInContentProcess. In contrast, using IsToplevel would only + // include documents that aren't embedded; e.g. tab documents. + if (doc->IsTopLevelInContentProcess()) { return doc; } } @@ -1122,6 +1126,7 @@ mozilla::ipc::IPCResult BrowserParent::RecvPDocAccessibleConstructor( // In this case, we don't get aParentDoc and aParentID. MOZ_ASSERT(!aParentDoc && !aParentID); MOZ_ASSERT(embedderID); + doc->SetTopLevelInContentProcess(); # ifdef XP_WIN MOZ_ASSERT(!aDocCOMProxy.IsNull()); RefPtr proxy(aDocCOMProxy.Get()); diff --git a/dom/ipc/BrowserParent.h b/dom/ipc/BrowserParent.h index 2efdd9b5bf5a..a5ec81767874 100644 --- a/dom/ipc/BrowserParent.h +++ b/dom/ipc/BrowserParent.h @@ -162,7 +162,12 @@ class BrowserParent final : public PBrowserParent, nsIXULBrowserWindow* GetXULBrowserWindow(); /** - * Return the top level doc accessible parent for this tab. + * Return the top level DocAccessibleParent for this BrowserParent. + * Note that in the case of an out-of-process iframe, the returned actor + * might not be at the top level of the DocAccessibleParent tree; i.e. it + * might have a parent. However, it will be at the top level in its content + * process. That is, doc->IsTopLevelInContentProcess() will always be true, + * but doc->IsTopLevel() might not. */ a11y::DocAccessibleParent* GetTopLevelDocAccessible() const;