summaryrefslogtreecommitdiffstats
path: root/accessible/generic/OuterDocAccessible.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/generic/OuterDocAccessible.cpp')
-rw-r--r--accessible/generic/OuterDocAccessible.cpp244
1 files changed, 244 insertions, 0 deletions
diff --git a/accessible/generic/OuterDocAccessible.cpp b/accessible/generic/OuterDocAccessible.cpp
new file mode 100644
index 0000000000..02d4e08a1e
--- /dev/null
+++ b/accessible/generic/OuterDocAccessible.cpp
@@ -0,0 +1,244 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "OuterDocAccessible.h"
+
+#include "Accessible-inl.h"
+#include "nsAccUtils.h"
+#include "DocAccessible-inl.h"
+#include "mozilla/a11y/DocAccessibleChild.h"
+#include "mozilla/a11y/DocAccessibleParent.h"
+#if defined(XP_WIN)
+# include "mozilla/a11y/ProxyWrappers.h"
+#endif
+#include "mozilla/dom/BrowserBridgeChild.h"
+#include "mozilla/dom/BrowserParent.h"
+#include "Role.h"
+#include "States.h"
+
+#ifdef A11Y_LOG
+# include "Logging.h"
+#endif
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// OuterDocAccessible
+////////////////////////////////////////////////////////////////////////////////
+
+OuterDocAccessible::OuterDocAccessible(nsIContent* aContent,
+ DocAccessible* aDoc)
+ : AccessibleWrap(aContent, aDoc) {
+ mType = eOuterDocType;
+
+#ifdef XP_WIN
+ if (DocAccessibleParent* remoteDoc = RemoteChildDoc()) {
+ remoteDoc->SendParentCOMProxy(this);
+ }
+#endif
+
+ if (IPCAccessibilityActive()) {
+ auto bridge = dom::BrowserBridgeChild::GetFrom(aContent);
+ if (bridge) {
+ // This is an iframe which will be rendered in another process.
+ SendEmbedderAccessible(bridge);
+ }
+ }
+
+ // Request document accessible for the content document to make sure it's
+ // created. It will appended to outerdoc accessible children asynchronously.
+ dom::Document* outerDoc = mContent->GetUncomposedDoc();
+ if (outerDoc) {
+ dom::Document* innerDoc = outerDoc->GetSubDocumentFor(mContent);
+ if (innerDoc) GetAccService()->GetDocAccessible(innerDoc);
+ }
+}
+
+OuterDocAccessible::~OuterDocAccessible() {}
+
+void OuterDocAccessible::SendEmbedderAccessible(
+ dom::BrowserBridgeChild* aBridge) {
+ MOZ_ASSERT(mDoc);
+ DocAccessibleChild* ipcDoc = mDoc->IPCDoc();
+ if (ipcDoc) {
+ uint64_t id = reinterpret_cast<uintptr_t>(UniqueID());
+#if defined(XP_WIN)
+ ipcDoc->SetEmbedderOnBridge(aBridge, id);
+#else
+ aBridge->SendSetEmbedderAccessible(ipcDoc, id);
+#endif
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Accessible public (DON'T add methods here)
+
+role OuterDocAccessible::NativeRole() const { return roles::INTERNAL_FRAME; }
+
+Accessible* OuterDocAccessible::ChildAtPoint(int32_t aX, int32_t aY,
+ EWhichChildAtPoint aWhichChild) {
+ nsIntRect docRect = Bounds();
+ if (!docRect.Contains(aX, aY)) return nullptr;
+
+ // Always return the inner doc as direct child accessible unless bounds
+ // outside of it.
+ Accessible* child = GetChildAt(0);
+ NS_ENSURE_TRUE(child, nullptr);
+
+ if (aWhichChild == eDeepestChild) {
+#if defined(XP_WIN)
+ // On Windows, OuterDocAccessible::GetChildAt can return a proxy wrapper
+ // for a remote document. These aren't real Accessibles and
+ // shouldn't be returned except to the Windows a11y code (which doesn't use
+ // eDeepestChild). Calling ChildAtPoint on these will crash!
+ return nullptr;
+#else
+ return child->ChildAtPoint(aX, aY, eDeepestChild);
+#endif // defined(XP_WIN)
+ }
+ return child;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Accessible public
+
+void OuterDocAccessible::Shutdown() {
+#ifdef A11Y_LOG
+ if (logging::IsEnabled(logging::eDocDestroy)) logging::OuterDocDestroy(this);
+#endif
+
+ Accessible* child = mChildren.SafeElementAt(0, nullptr);
+ if (child) {
+#ifdef A11Y_LOG
+ if (logging::IsEnabled(logging::eDocDestroy)) {
+ logging::DocDestroy("outerdoc's child document rebind is scheduled",
+ child->AsDoc()->DocumentNode());
+ }
+#endif
+ RemoveChild(child);
+
+ // XXX: sometimes outerdoc accessible is shutdown because of layout style
+ // change however the presshell of underlying document isn't destroyed and
+ // the document doesn't get pagehide events. Schedule a document rebind
+ // to its parent document. Otherwise a document accessible may be lost if
+ // its outerdoc has being recreated (see bug 862863 for details).
+ if (!mDoc->IsDefunct()) {
+ MOZ_ASSERT(!child->IsDefunct(),
+ "Attempt to reattach shutdown document accessible");
+ if (!child->IsDefunct()) {
+ mDoc->BindChildDocument(child->AsDoc());
+ }
+ }
+ }
+
+ AccessibleWrap::Shutdown();
+}
+
+bool OuterDocAccessible::InsertChildAt(uint32_t aIdx, Accessible* aAccessible) {
+ MOZ_RELEASE_ASSERT(aAccessible->IsDoc(),
+ "OuterDocAccessible can have a document child only!");
+
+ // We keep showing the old document for a bit after creating the new one,
+ // and while building the new DOM and frame tree. That's done on purpose
+ // to avoid weird flashes of default background color.
+ // The old viewer will be destroyed after the new one is created.
+ // For a11y, it should be safe to shut down the old document now.
+ if (mChildren.Length()) mChildren[0]->Shutdown();
+
+ if (!AccessibleWrap::InsertChildAt(0, aAccessible)) return false;
+
+#ifdef A11Y_LOG
+ if (logging::IsEnabled(logging::eDocCreate)) {
+ logging::DocCreate("append document to outerdoc",
+ aAccessible->AsDoc()->DocumentNode());
+ logging::Address("outerdoc", this);
+ }
+#endif
+
+ return true;
+}
+
+bool OuterDocAccessible::RemoveChild(Accessible* aAccessible) {
+ Accessible* child = mChildren.SafeElementAt(0, nullptr);
+ MOZ_ASSERT(child == aAccessible, "Wrong child to remove!");
+ if (child != aAccessible) {
+ return false;
+ }
+
+#ifdef A11Y_LOG
+ if (logging::IsEnabled(logging::eDocDestroy)) {
+ logging::DocDestroy("remove document from outerdoc",
+ child->AsDoc()->DocumentNode(), child->AsDoc());
+ logging::Address("outerdoc", this);
+ }
+#endif
+
+ bool wasRemoved = AccessibleWrap::RemoveChild(child);
+
+ NS_ASSERTION(!mChildren.Length(),
+ "This child document of outerdoc accessible wasn't removed!");
+
+ return wasRemoved;
+}
+
+bool OuterDocAccessible::IsAcceptableChild(nsIContent* aEl) const {
+ // outer document accessible doesn't not participate in ordinal tree
+ // mutations.
+ return false;
+}
+
+#if defined(XP_WIN)
+
+Accessible* OuterDocAccessible::RemoteChildDocAccessible() const {
+ ProxyAccessible* docProxy = RemoteChildDoc();
+ if (docProxy) {
+ // We're in the parent process, but we're embedding a remote document.
+ return WrapperFor(docProxy);
+ }
+
+ if (IPCAccessibilityActive()) {
+ auto bridge = dom::BrowserBridgeChild::GetFrom(mContent);
+ if (bridge) {
+ // We're an iframe in a content process and we're embedding a remote
+ // document (in another content process). The COM proxy for the embedded
+ // document accessible was sent to us from the parent via PBrowserBridge.
+ return bridge->GetEmbeddedDocAccessible();
+ }
+ }
+
+ return nullptr;
+}
+
+// On Windows e10s, since we don't cache in the chrome process, these next two
+// functions must be implemented so that we properly cross the chrome-to-content
+// boundary when traversing.
+
+uint32_t OuterDocAccessible::ChildCount() const {
+ uint32_t result = mChildren.Length();
+ if (!result && RemoteChildDocAccessible()) {
+ result = 1;
+ }
+ return result;
+}
+
+Accessible* OuterDocAccessible::GetChildAt(uint32_t aIndex) const {
+ Accessible* result = AccessibleWrap::GetChildAt(aIndex);
+ if (result || aIndex) {
+ return result;
+ }
+ // If we are asking for child 0 and GetChildAt doesn't return anything, try
+ // to get the remote child doc and return that instead.
+ return RemoteChildDocAccessible();
+}
+
+#endif // defined(XP_WIN)
+
+DocAccessibleParent* OuterDocAccessible::RemoteChildDoc() const {
+ dom::BrowserParent* tab = dom::BrowserParent::GetFrom(GetContent());
+ if (!tab) return nullptr;
+
+ return tab->GetTopLevelDocAccessible();
+}