summaryrefslogtreecommitdiff
path: root/accessible/ipc
diff options
context:
space:
mode:
authorPale Moon <git-repo@palemoon.org>2016-09-01 13:39:08 +0200
committerPale Moon <git-repo@palemoon.org>2016-09-01 13:39:08 +0200
commit3d8ce1a11a7347cc94a937719c4bc8df46fb8d14 (patch)
tree8c26ca375a6312751c00a27e1653fb6f189f0463 /accessible/ipc
parente449bdb1ec3a82f204bffdd9c3c54069d086eee3 (diff)
downloadpalemoon-gre-3d8ce1a11a7347cc94a937719c4bc8df46fb8d14.tar.gz
Base import of Tycho code (warning: huge commit)
Diffstat (limited to 'accessible/ipc')
-rw-r--r--accessible/ipc/DocAccessibleChild.cpp280
-rw-r--r--accessible/ipc/DocAccessibleChild.h94
-rw-r--r--accessible/ipc/DocAccessibleParent.cpp181
-rw-r--r--accessible/ipc/DocAccessibleParent.h138
-rw-r--r--accessible/ipc/PDocAccessible.ipdl79
-rw-r--r--accessible/ipc/ProxyAccessible.cpp190
-rw-r--r--accessible/ipc/ProxyAccessible.h157
-rw-r--r--accessible/ipc/moz.build33
8 files changed, 1152 insertions, 0 deletions
diff --git a/accessible/ipc/DocAccessibleChild.cpp b/accessible/ipc/DocAccessibleChild.cpp
new file mode 100644
index 000000000..bf3672a92
--- /dev/null
+++ b/accessible/ipc/DocAccessibleChild.cpp
@@ -0,0 +1,280 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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 "DocAccessibleChild.h"
+
+#include "Accessible-inl.h"
+#include "ProxyAccessible.h"
+#include "Relation.h"
+
+#include "nsIPersistentProperties2.h"
+#include "nsISimpleEnumerator.h"
+
+namespace mozilla {
+namespace a11y {
+
+static uint32_t
+InterfacesFor(Accessible* aAcc)
+{
+ uint32_t interfaces = 0;
+ if (aAcc->IsHyperText() && aAcc->AsHyperText()->IsTextRole())
+ interfaces |= Interfaces::HYPERTEXT;
+
+ return interfaces;
+}
+
+static void
+SerializeTree(Accessible* aRoot, nsTArray<AccessibleData>& aTree)
+{
+ uint64_t id = reinterpret_cast<uint64_t>(aRoot->UniqueID());
+ uint32_t role = aRoot->Role();
+ uint32_t childCount = aRoot->ChildCount();
+ uint32_t interfaces = InterfacesFor(aRoot);
+
+ // OuterDocAccessibles are special because we don't want to serialize the
+ // child doc here, we'll call PDocAccessibleConstructor in
+ // NotificationController.
+ if (childCount == 1 && aRoot->GetChildAt(0)->IsDoc())
+ childCount = 0;
+
+ aTree.AppendElement(AccessibleData(id, role, childCount, interfaces));
+ for (uint32_t i = 0; i < childCount; i++)
+ SerializeTree(aRoot->GetChildAt(i), aTree);
+}
+
+Accessible*
+DocAccessibleChild::IdToAccessible(const uint64_t& aID)
+{
+ return mDoc->GetAccessibleByUniqueID(reinterpret_cast<void*>(aID));
+}
+
+HyperTextAccessible*
+DocAccessibleChild::IdToHyperTextAccessible(const uint64_t& aID)
+{
+ Accessible* acc = IdToAccessible(aID);
+ MOZ_ASSERT(!acc || acc->IsHyperText());
+ return acc ? acc->AsHyperText() : nullptr;
+}
+
+void
+DocAccessibleChild::ShowEvent(AccShowEvent* aShowEvent)
+{
+ Accessible* parent = aShowEvent->Parent();
+ uint64_t parentID = parent->IsDoc() ? 0 : reinterpret_cast<uint64_t>(parent->UniqueID());
+ uint32_t idxInParent = aShowEvent->GetAccessible()->IndexInParent();
+ nsTArray<AccessibleData> shownTree;
+ ShowEventData data(parentID, idxInParent, shownTree);
+ SerializeTree(aShowEvent->GetAccessible(), data.NewTree());
+ SendShowEvent(data);
+}
+
+bool
+DocAccessibleChild::RecvState(const uint64_t& aID, uint64_t* aState)
+{
+ Accessible* acc = IdToAccessible(aID);
+ if (!acc) {
+ *aState = states::DEFUNCT;
+ return true;
+ }
+
+ *aState = acc->State();
+
+ return true;
+}
+
+bool
+DocAccessibleChild::RecvName(const uint64_t& aID, nsString* aName)
+{
+ Accessible* acc = IdToAccessible(aID);
+ if (!acc)
+ return true;
+
+ acc->Name(*aName);
+ return true;
+}
+
+bool
+DocAccessibleChild::RecvValue(const uint64_t& aID, nsString* aValue)
+{
+ Accessible* acc = IdToAccessible(aID);
+ if (!acc) {
+ return true;
+ }
+
+ acc->Value(*aValue);
+ return true;
+}
+
+bool
+DocAccessibleChild::RecvDescription(const uint64_t& aID, nsString* aDesc)
+{
+ Accessible* acc = IdToAccessible(aID);
+ if (!acc)
+ return true;
+
+ acc->Description(*aDesc);
+ return true;
+}
+
+bool
+DocAccessibleChild::RecvAttributes(const uint64_t& aID, nsTArray<Attribute>* aAttributes)
+{
+ Accessible* acc = IdToAccessible(aID);
+ if (!acc)
+ return true;
+
+ nsCOMPtr<nsIPersistentProperties> props = acc->Attributes();
+ if (!props)
+ return true;
+
+ nsCOMPtr<nsISimpleEnumerator> propEnum;
+ nsresult rv = props->Enumerate(getter_AddRefs(propEnum));
+ NS_ENSURE_SUCCESS(rv, false);
+
+ bool hasMore;
+ while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
+ nsCOMPtr<nsISupports> sup;
+ rv = propEnum->GetNext(getter_AddRefs(sup));
+ NS_ENSURE_SUCCESS(rv, false);
+
+ nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup));
+ NS_ENSURE_TRUE(propElem, false);
+
+ nsAutoCString name;
+ rv = propElem->GetKey(name);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ nsAutoString value;
+ rv = propElem->GetValue(value);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ aAttributes->AppendElement(Attribute(name, value));
+ }
+
+ return true;
+}
+
+bool
+DocAccessibleChild::RecvRelationByType(const uint64_t& aID,
+ const uint32_t& aType,
+ nsTArray<uint64_t>* aTargets)
+{
+ Accessible* acc = mDoc->GetAccessibleByUniqueID((void*)aID);
+ if (!acc)
+ return false;
+
+ auto type = static_cast<RelationType>(aType);
+ Relation rel = acc->RelationByType(type);
+ while (Accessible* target = rel.Next())
+ aTargets->AppendElement(reinterpret_cast<uintptr_t>(target));
+
+ return true;
+}
+
+static void
+AddRelation(Accessible* aAcc, RelationType aType,
+ nsTArray<RelationTargets>* aTargets)
+{
+ Relation rel = aAcc->RelationByType(aType);
+ nsTArray<uint64_t> targets;
+ while (Accessible* target = rel.Next())
+ targets.AppendElement(reinterpret_cast<uintptr_t>(target));
+
+ if (!targets.IsEmpty()) {
+ RelationTargets* newRelation =
+ aTargets->AppendElement(RelationTargets(static_cast<uint32_t>(aType),
+ nsTArray<uint64_t>()));
+ newRelation->Targets().SwapElements(targets);
+ }
+}
+
+bool
+DocAccessibleChild::RecvRelations(const uint64_t& aID,
+ nsTArray<RelationTargets>* aRelations)
+{
+ Accessible* acc = mDoc->GetAccessibleByUniqueID((void*)aID);
+ if (!aID)
+ return false;
+
+#define RELATIONTYPE(goanna, s, a, m, i) AddRelation(acc, RelationType::goanna, aRelations);
+
+#include "RelationTypeMap.h"
+#undef RELATIONTYPE
+
+ return true;
+}
+
+bool
+DocAccessibleChild::RecvTextSubstring(const uint64_t& aID,
+ const int32_t& aStartOffset,
+ const int32_t& aEndOffset,
+ nsString* aText)
+{
+ HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
+ if (!acc) {
+ return true;
+ }
+
+ acc->TextSubstring(aStartOffset, aEndOffset, *aText);
+ return true;
+}
+
+bool
+DocAccessibleChild::RecvGetTextAfterOffset(const uint64_t& aID,
+ const int32_t& aOffset,
+ const int32_t& aBoundaryType,
+ nsString* aText,
+ int32_t* aStartOffset,
+ int32_t* aEndOffset)
+{
+ *aStartOffset = 0;
+ *aEndOffset = 0;
+ HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
+ if (acc) {
+ acc->TextAfterOffset(aOffset, aBoundaryType,
+ aStartOffset, aEndOffset, *aText);
+ }
+ return true;
+}
+
+bool
+DocAccessibleChild::RecvGetTextAtOffset(const uint64_t& aID,
+ const int32_t& aOffset,
+ const int32_t& aBoundaryType,
+ nsString* aText,
+ int32_t* aStartOffset,
+ int32_t* aEndOffset)
+{
+ *aStartOffset = 0;
+ *aEndOffset = 0;
+ HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
+ if (acc) {
+ acc->TextAtOffset(aOffset, aBoundaryType,
+ aStartOffset, aEndOffset, *aText);
+ }
+ return true;
+}
+
+bool
+DocAccessibleChild::RecvGetTextBeforeOffset(const uint64_t& aID,
+ const int32_t& aOffset,
+ const int32_t& aBoundaryType,
+ nsString* aText,
+ int32_t* aStartOffset,
+ int32_t* aEndOffset)
+{
+ *aStartOffset = 0;
+ *aEndOffset = 0;
+ HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
+ if (acc) {
+ acc->TextBeforeOffset(aOffset, aBoundaryType,
+ aStartOffset, aEndOffset, *aText);
+ }
+ return true;
+}
+
+}
+}
diff --git a/accessible/ipc/DocAccessibleChild.h b/accessible/ipc/DocAccessibleChild.h
new file mode 100644
index 000000000..b6d17729e
--- /dev/null
+++ b/accessible/ipc/DocAccessibleChild.h
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_a11y_DocAccessibleChild_h
+#define mozilla_a11y_DocAccessibleChild_h
+
+#include "mozilla/a11y/DocAccessible.h"
+#include "mozilla/a11y/PDocAccessibleChild.h"
+#include "nsISupportsImpl.h"
+
+namespace mozilla {
+namespace a11y {
+class Accessible;
+class HyperTextAccessible;
+
+class AccShowEvent;
+
+ /*
+ * These objects handle content side communication for an accessible document,
+ * and their lifetime is the same as the document they represent.
+ */
+class DocAccessibleChild : public PDocAccessibleChild
+{
+public:
+ explicit DocAccessibleChild(DocAccessible* aDoc) :
+ mDoc(aDoc)
+ { MOZ_COUNT_CTOR(DocAccessibleChild); }
+ ~DocAccessibleChild()
+ {
+ mDoc->SetIPCDoc(nullptr);
+ MOZ_COUNT_DTOR(DocAccessibleChild);
+ }
+
+ Accessible* IdToAccessible(const uint64_t& aID);
+ HyperTextAccessible* IdToHyperTextAccessible(const uint64_t& aID);
+
+ void ShowEvent(AccShowEvent* aShowEvent);
+
+ /*
+ * Return the state for the accessible with given ID.
+ */
+ virtual bool RecvState(const uint64_t& aID, uint64_t* aState) override;
+
+ /*
+ * Get the name for the accessible with given id.
+ */
+ virtual bool RecvName(const uint64_t& aID, nsString* aName) override;
+
+ virtual bool RecvValue(const uint64_t& aID, nsString* aValue) override;
+
+ /*
+ * Get the description for the accessible with given id.
+ */
+ virtual bool RecvDescription(const uint64_t& aID, nsString* aDesc) override;
+ virtual bool RecvRelationByType(const uint64_t& aID, const uint32_t& aType,
+ nsTArray<uint64_t>* aTargets) override;
+ virtual bool RecvRelations(const uint64_t& aID,
+ nsTArray<RelationTargets>* aRelations)
+ override;
+
+ virtual bool RecvAttributes(const uint64_t& aID,
+ nsTArray<Attribute> *aAttributes) override;
+ virtual bool RecvTextSubstring(const uint64_t& aID,
+ const int32_t& aStartOffset,
+ const int32_t& aEndOffset, nsString* aText)
+ override;
+
+ virtual bool RecvGetTextAfterOffset(const uint64_t& aID,
+ const int32_t& aOffset,
+ const int32_t& aBoundaryType,
+ nsString* aText, int32_t* aStartOffset,
+ int32_t* aEndOffset) override;
+ virtual bool RecvGetTextAtOffset(const uint64_t& aID,
+ const int32_t& aOffset,
+ const int32_t& aBoundaryType,
+ nsString* aText, int32_t* aStartOffset,
+ int32_t* aEndOffset) override;
+ virtual bool RecvGetTextBeforeOffset(const uint64_t& aID,
+ const int32_t& aOffset,
+ const int32_t& aBoundaryType,
+ nsString* aText, int32_t* aStartOffset,
+ int32_t* aEndOffset) override;
+
+private:
+ DocAccessible* mDoc;
+};
+
+}
+}
+
+#endif
diff --git a/accessible/ipc/DocAccessibleParent.cpp b/accessible/ipc/DocAccessibleParent.cpp
new file mode 100644
index 000000000..38b41357e
--- /dev/null
+++ b/accessible/ipc/DocAccessibleParent.cpp
@@ -0,0 +1,181 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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 "DocAccessibleParent.h"
+#include "nsAutoPtr.h"
+#include "mozilla/a11y/Platform.h"
+#include "ProxyAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+bool
+DocAccessibleParent::RecvShowEvent(const ShowEventData& aData)
+{
+ if (mShutdown)
+ return true;
+
+ if (aData.NewTree().IsEmpty()) {
+ NS_ERROR("no children being added");
+ return false;
+ }
+
+ ProxyAccessible* parent = nullptr;
+ if (aData.ID()) {
+ ProxyEntry* e = mAccessibles.GetEntry(aData.ID());
+ if (e)
+ parent = e->mProxy;
+ } else {
+ parent = this;
+ }
+
+ // XXX This should really never happen, but sometimes we fail to fire the
+ // required show events.
+ if (!parent) {
+ NS_ERROR("adding child to unknown accessible");
+ return false;
+ }
+
+ uint32_t newChildIdx = aData.Idx();
+ if (newChildIdx > parent->ChildrenCount()) {
+ NS_ERROR("invalid index to add child at");
+ return false;
+ }
+
+ uint32_t consumed = AddSubtree(parent, aData.NewTree(), 0, newChildIdx);
+ MOZ_ASSERT(consumed == aData.NewTree().Length());
+#ifdef DEBUG
+ for (uint32_t i = 0; i < consumed; i++) {
+ uint64_t id = aData.NewTree()[i].ID();
+ MOZ_ASSERT(mAccessibles.GetEntry(id));
+ }
+#endif
+
+ return consumed != 0;
+}
+
+uint32_t
+DocAccessibleParent::AddSubtree(ProxyAccessible* aParent,
+ const nsTArray<a11y::AccessibleData>& aNewTree,
+ uint32_t aIdx, uint32_t aIdxInParent)
+{
+ if (aNewTree.Length() <= aIdx) {
+ NS_ERROR("bad index in serialized tree!");
+ return 0;
+ }
+
+ const AccessibleData& newChild = aNewTree[aIdx];
+ if (newChild.Role() > roles::LAST_ROLE) {
+ NS_ERROR("invalid role");
+ return 0;
+ }
+
+ auto role = static_cast<a11y::role>(newChild.Role());
+ ProxyAccessible* newProxy =
+ new ProxyAccessible(newChild.ID(), aParent, this, role);
+ aParent->AddChildAt(aIdxInParent, newProxy);
+ mAccessibles.PutEntry(newChild.ID())->mProxy = newProxy;
+ ProxyCreated(newProxy, newChild.Interfaces());
+
+ uint32_t accessibles = 1;
+ uint32_t kids = newChild.ChildrenCount();
+ for (uint32_t i = 0; i < kids; i++) {
+ uint32_t consumed = AddSubtree(newProxy, aNewTree, aIdx + accessibles, i);
+ if (!consumed)
+ return 0;
+
+ accessibles += consumed;
+ }
+
+ MOZ_ASSERT(newProxy->ChildrenCount() == kids);
+
+ return accessibles;
+}
+
+bool
+DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID)
+{
+ if (mShutdown)
+ return true;
+
+ ProxyEntry* rootEntry = mAccessibles.GetEntry(aRootID);
+ if (!rootEntry) {
+ NS_ERROR("invalid root being removed!");
+ return true;
+ }
+
+ ProxyAccessible* root = rootEntry->mProxy;
+ if (!root) {
+ NS_ERROR("invalid root being removed!");
+ return true;
+ }
+
+ ProxyAccessible* parent = root->Parent();
+ parent->RemoveChild(root);
+ root->Shutdown();
+
+ return true;
+}
+
+bool
+DocAccessibleParent::RecvEvent(const uint64_t& aID, const uint32_t& aEventType)
+{
+ if (!aID) {
+ ProxyEvent(this, aEventType);
+ return true;
+ }
+
+ ProxyEntry* e = mAccessibles.GetEntry(aID);
+ if (!e) {
+ NS_ERROR("no proxy for event!");
+ return true;
+ }
+
+ ProxyEvent(e->mProxy, aEventType);
+ return true;
+}
+bool
+DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
+ uint64_t aParentID)
+{
+ ProxyAccessible* outerDoc = mAccessibles.GetEntry(aParentID)->mProxy;
+ if (!outerDoc)
+ return false;
+
+ aChildDoc->mParent = outerDoc;
+ outerDoc->SetChildDoc(aChildDoc);
+ mChildDocs.AppendElement(aChildDoc);
+ aChildDoc->mParentDoc = this;
+ ProxyCreated(aChildDoc, 0);
+ return true;
+}
+
+PLDHashOperator
+DocAccessibleParent::ShutdownAccessibles(ProxyEntry* entry, void*)
+{
+ ProxyDestroyed(entry->mProxy);
+ return PL_DHASH_REMOVE;
+}
+
+void
+DocAccessibleParent::Destroy()
+{
+ NS_ASSERTION(mChildDocs.IsEmpty(),
+ "why weren't the child docs destroyed already?");
+ MOZ_ASSERT(!mShutdown);
+ mShutdown = true;
+
+ uint32_t childDocCount = mChildDocs.Length();
+ for (uint32_t i = childDocCount - 1; i < childDocCount; i--)
+ mChildDocs[i]->Destroy();
+
+ mAccessibles.EnumerateEntries(ShutdownAccessibles, nullptr);
+ ProxyDestroyed(this);
+ mParentDoc ? mParentDoc->RemoveChildDoc(this)
+ : GetAccService()->RemoteDocShutdown(this);
+}
+}
+}
diff --git a/accessible/ipc/DocAccessibleParent.h b/accessible/ipc/DocAccessibleParent.h
new file mode 100644
index 000000000..369dd5f49
--- /dev/null
+++ b/accessible/ipc/DocAccessibleParent.h
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_a11y_DocAccessibleParent_h
+#define mozilla_a11y_DocAccessibleParent_h
+
+#include "nsAccessibilityService.h"
+#include "ProxyAccessible.h"
+#include "mozilla/a11y/PDocAccessibleParent.h"
+#include "nsClassHashtable.h"
+#include "nsHashKeys.h"
+#include "nsISupportsImpl.h"
+
+namespace mozilla {
+namespace a11y {
+
+/*
+ * These objects live in the main process and comunicate with and represent
+ * an accessible document in a content process.
+ */
+class DocAccessibleParent : public ProxyAccessible,
+ public PDocAccessibleParent
+{
+public:
+ DocAccessibleParent() :
+ ProxyAccessible(this), mParentDoc(nullptr), mShutdown(false)
+ { MOZ_COUNT_CTOR_INHERITED(DocAccessibleParent, ProxyAccessible); }
+ ~DocAccessibleParent()
+ {
+ MOZ_COUNT_DTOR_INHERITED(DocAccessibleParent, ProxyAccessible);
+ MOZ_ASSERT(mChildDocs.Length() == 0);
+ MOZ_ASSERT(!mParentDoc);
+ }
+
+ /*
+ * Called when a message from a document in a child process notifies the main
+ * process it is firing an event.
+ */
+ virtual bool RecvEvent(const uint64_t& aID, const uint32_t& aType)
+ override;
+
+ virtual bool RecvShowEvent(const ShowEventData& aData) override;
+ virtual bool RecvHideEvent(const uint64_t& aRootID) override;
+
+ void Destroy();
+ virtual void ActorDestroy(ActorDestroyReason aWhy) override
+ {
+ if (!mShutdown)
+ Destroy();
+ }
+
+ /*
+ * Return the main processes representation of the parent document (if any)
+ * of the document this object represents.
+ */
+ DocAccessibleParent* Parent() const { return mParentDoc; }
+
+ /*
+ * Called when a document in a content process notifies the main process of a
+ * new child document.
+ */
+ bool AddChildDoc(DocAccessibleParent* aChildDoc, uint64_t aParentID);
+
+ /*
+ * Called when the document in the content process this object represents
+ * notifies the main process a child document has been removed.
+ */
+ void RemoveChildDoc(DocAccessibleParent* aChildDoc)
+ {
+ aChildDoc->mParent->SetChildDoc(nullptr);
+ mChildDocs.RemoveElement(aChildDoc);
+ aChildDoc->mParentDoc = nullptr;
+ MOZ_ASSERT(aChildDoc->mChildDocs.Length() == 0);
+ }
+
+ void RemoveAccessible(ProxyAccessible* aAccessible)
+ {
+ MOZ_ASSERT(mAccessibles.GetEntry(aAccessible->ID()));
+ mAccessibles.RemoveEntry(aAccessible->ID());
+ }
+
+ /**
+ * Return the accessible for given id.
+ */
+ ProxyAccessible* GetAccessible(uintptr_t aID) const
+ {
+ ProxyEntry* e = mAccessibles.GetEntry(aID);
+ return e ? e->mProxy : nullptr;
+ }
+
+private:
+
+ class ProxyEntry : public PLDHashEntryHdr
+ {
+ public:
+ explicit ProxyEntry(const void*) : mProxy(nullptr) {}
+ ProxyEntry(ProxyEntry&& aOther) :
+ mProxy(aOther.mProxy) { aOther.mProxy = nullptr; }
+ ~ProxyEntry() { delete mProxy; }
+
+ typedef uint64_t KeyType;
+ typedef const void* KeyTypePointer;
+
+ bool KeyEquals(const void* aKey) const
+ { return mProxy->ID() == (uint64_t)aKey; }
+
+ static const void* KeyToPointer(uint64_t aKey) { return (void*)aKey; }
+
+ static PLDHashNumber HashKey(const void* aKey) { return (uint64_t)aKey; }
+
+ enum { ALLOW_MEMMOVE = true };
+
+ ProxyAccessible* mProxy;
+ };
+
+ uint32_t AddSubtree(ProxyAccessible* aParent,
+ const nsTArray<AccessibleData>& aNewTree, uint32_t aIdx,
+ uint32_t aIdxInParent);
+ static PLDHashOperator ShutdownAccessibles(ProxyEntry* entry, void* unused);
+
+ nsTArray<DocAccessibleParent*> mChildDocs;
+ DocAccessibleParent* mParentDoc;
+
+ /*
+ * Conceptually this is a map from IDs to proxies, but we store the ID in the
+ * proxy object so we can't use a real map.
+ */
+ nsTHashtable<ProxyEntry> mAccessibles;
+ bool mShutdown;
+};
+
+}
+}
+
+#endif
diff --git a/accessible/ipc/PDocAccessible.ipdl b/accessible/ipc/PDocAccessible.ipdl
new file mode 100644
index 000000000..7464787cd
--- /dev/null
+++ b/accessible/ipc/PDocAccessible.ipdl
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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 protocol PContent;
+
+namespace mozilla {
+namespace a11y {
+
+struct AccessibleData
+{
+ uint64_t ID;
+ uint32_t Role;
+ uint32_t ChildrenCount;
+ uint32_t Interfaces;
+};
+
+struct ShowEventData
+{
+ uint64_t ID;
+ uint32_t Idx;
+ AccessibleData[] NewTree;
+};
+
+struct Attribute
+{
+ nsCString Name;
+ nsString Value;
+};
+
+struct RelationTargets
+{
+ uint32_t Type;
+ uint64_t[] Targets;
+};
+
+prio(normal upto high) sync protocol PDocAccessible
+{
+ manager PContent;
+
+parent:
+ __delete__();
+
+ /*
+ * Notify the parent process the document in the child process is firing an
+ * event.
+ */
+ Event(uint64_t aID, uint32_t type);
+ ShowEvent(ShowEventData data);
+ HideEvent(uint64_t aRootID);
+
+child:
+ // Accessible
+ prio(high) sync State(uint64_t aID) returns(uint64_t states);
+ prio(high) sync Name(uint64_t aID) returns(nsString name);
+ prio(high) sync Value(uint64_t aID) returns(nsString value);
+ prio(high) sync Description(uint64_t aID) returns(nsString desc);
+ prio(high) sync Attributes(uint64_t aID) returns(Attribute[] attributes);
+ prio(high) sync RelationByType(uint64_t aID, uint32_t aRelationType)
+ returns(uint64_t[] targets);
+ prio(high) sync Relations(uint64_t aID) returns(RelationTargets[] relations);
+
+ // AccessibleText
+
+ // TextSubstring is getText in IDL.
+ prio(high) sync TextSubstring(uint64_t aID, int32_t aStartOffset, int32_t
+ aEndOffset) returns(nsString aText);
+ prio(high) sync GetTextAfterOffset(uint64_t aID, int32_t aOffset, int32_t aBoundaryType)
+ returns(nsString aText, int32_t aStartOffset, int32_t aEndOffset);
+ prio(high) sync GetTextAtOffset(uint64_t aID, int32_t aOffset, int32_t aBoundaryType)
+ returns(nsString aText, int32_t aStartOffset, int32_t aEndOffset);
+ prio(high) sync GetTextBeforeOffset(uint64_t aID, int32_t aOffset, int32_t aBoundaryType)
+ returns(nsString aText, int32_t aStartOffset, int32_t aEndOffset);
+};
+
+}
+}
diff --git a/accessible/ipc/ProxyAccessible.cpp b/accessible/ipc/ProxyAccessible.cpp
new file mode 100644
index 000000000..8dd034c50
--- /dev/null
+++ b/accessible/ipc/ProxyAccessible.cpp
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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 "ProxyAccessible.h"
+#include "DocAccessibleParent.h"
+#include "mozilla/unused.h"
+#include "mozilla/a11y/Platform.h"
+#include "RelationType.h"
+#include "mozilla/a11y/Role.h"
+
+namespace mozilla {
+namespace a11y {
+
+void
+ProxyAccessible::Shutdown()
+{
+ NS_ASSERTION(!mOuterDoc, "Why do we still have a child doc?");
+
+ // XXX Ideally this wouldn't be necessary, but it seems OuterDoc accessibles
+ // can be destroyed before the doc they own.
+ if (!mOuterDoc) {
+ uint32_t childCount = mChildren.Length();
+ for (uint32_t idx = 0; idx < childCount; idx++)
+ mChildren[idx]->Shutdown();
+ } else {
+ if (mChildren.Length() != 1)
+ MOZ_CRASH("outer doc doesn't own adoc!");
+
+ static_cast<DocAccessibleParent*>(mChildren[0])->Destroy();
+ }
+
+ mChildren.Clear();
+ ProxyDestroyed(this);
+ mDoc->RemoveAccessible(this);
+}
+
+void
+ProxyAccessible::SetChildDoc(DocAccessibleParent* aParent)
+{
+ if (aParent) {
+ MOZ_ASSERT(mChildren.IsEmpty());
+ mChildren.AppendElement(aParent);
+ mOuterDoc = true;
+ } else {
+ MOZ_ASSERT(mChildren.Length() == 1);
+ mChildren.Clear();
+ mOuterDoc = false;
+ }
+}
+
+bool
+ProxyAccessible::MustPruneChildren() const
+{
+ // this is the equivalent to nsAccUtils::MustPrune for proxies and should be
+ // kept in sync with that.
+ if (mRole != roles::MENUITEM && mRole != roles::COMBOBOX_OPTION
+ && mRole != roles::OPTION && mRole != roles::ENTRY
+ && mRole != roles::FLAT_EQUATION && mRole != roles::PASSWORD_TEXT
+ && mRole != roles::PUSHBUTTON && mRole != roles::TOGGLE_BUTTON
+ && mRole != roles::GRAPHIC && mRole != roles::SLIDER
+ && mRole != roles::PROGRESSBAR && mRole != roles::SEPARATOR)
+ return false;
+
+ if (mChildren.Length() != 1)
+ return false;
+
+ return mChildren[0]->Role() == roles::TEXT_LEAF
+ || mChildren[0]->Role() == roles::STATICTEXT;
+}
+
+uint64_t
+ProxyAccessible::State() const
+{
+ uint64_t state = 0;
+ unused << mDoc->SendState(mID, &state);
+ return state;
+}
+
+void
+ProxyAccessible::Name(nsString& aName) const
+{
+ unused << mDoc->SendName(mID, &aName);
+}
+
+void
+ProxyAccessible::Value(nsString& aValue) const
+{
+ unused << mDoc->SendValue(mID, &aValue);
+}
+
+void
+ProxyAccessible::Description(nsString& aDesc) const
+{
+ unused << mDoc->SendDescription(mID, &aDesc);
+}
+
+void
+ProxyAccessible::Attributes(nsTArray<Attribute> *aAttrs) const
+{
+ unused << mDoc->SendAttributes(mID, aAttrs);
+}
+
+nsTArray<ProxyAccessible*>
+ProxyAccessible::RelationByType(RelationType aType) const
+{
+ nsTArray<uint64_t> targetIDs;
+ unused << mDoc->SendRelationByType(mID, static_cast<uint32_t>(aType),
+ &targetIDs);
+
+ size_t targetCount = targetIDs.Length();
+ nsTArray<ProxyAccessible*> targets(targetCount);
+ for (size_t i = 0; i < targetCount; i++)
+ if (ProxyAccessible* proxy = mDoc->GetAccessible(targetIDs[i]))
+ targets.AppendElement(proxy);
+
+ return Move(targets);
+}
+
+void
+ProxyAccessible::Relations(nsTArray<RelationType>* aTypes,
+ nsTArray<nsTArray<ProxyAccessible*>>* aTargetSets)
+ const
+{
+ nsTArray<RelationTargets> ipcRelations;
+ unused << mDoc->SendRelations(mID, &ipcRelations);
+
+ size_t relationCount = ipcRelations.Length();
+ aTypes->SetCapacity(relationCount);
+ aTargetSets->SetCapacity(relationCount);
+ for (size_t i = 0; i < relationCount; i++) {
+ uint32_t type = ipcRelations[i].Type();
+ if (type > static_cast<uint32_t>(RelationType::LAST))
+ continue;
+
+ size_t targetCount = ipcRelations[i].Targets().Length();
+ nsTArray<ProxyAccessible*> targets(targetCount);
+ for (size_t j = 0; j < targetCount; j++)
+ if (ProxyAccessible* proxy = mDoc->GetAccessible(ipcRelations[i].Targets()[j]))
+ targets.AppendElement(proxy);
+
+ if (targets.IsEmpty())
+ continue;
+
+ aTargetSets->AppendElement(Move(targets));
+ aTypes->AppendElement(static_cast<RelationType>(type));
+ }
+}
+
+void
+ProxyAccessible::TextSubstring(int32_t aStartOffset, int32_t aEndOfset,
+ nsString& aText) const
+{
+ unused << mDoc->SendTextSubstring(mID, aStartOffset, aEndOfset, &aText);
+}
+
+void
+ProxyAccessible::GetTextAfterOffset(int32_t aOffset,
+ AccessibleTextBoundary aBoundaryType,
+ nsString& aText, int32_t* aStartOffset,
+ int32_t* aEndOffset)
+{
+ unused << mDoc->SendGetTextAfterOffset(mID, aOffset, aBoundaryType,
+ &aText, aStartOffset, aEndOffset);
+}
+
+void
+ProxyAccessible::GetTextAtOffset(int32_t aOffset,
+ AccessibleTextBoundary aBoundaryType,
+ nsString& aText, int32_t* aStartOffset,
+ int32_t* aEndOffset)
+{
+ unused << mDoc->SendGetTextAtOffset(mID, aOffset, aBoundaryType,
+ &aText, aStartOffset, aEndOffset);
+}
+
+void
+ProxyAccessible::GetTextBeforeOffset(int32_t aOffset,
+ AccessibleTextBoundary aBoundaryType,
+ nsString& aText, int32_t* aStartOffset,
+ int32_t* aEndOffset)
+{
+ unused << mDoc->SendGetTextBeforeOffset(mID, aOffset, aBoundaryType,
+ &aText, aStartOffset, aEndOffset);
+}
+
+}
+}
diff --git a/accessible/ipc/ProxyAccessible.h b/accessible/ipc/ProxyAccessible.h
new file mode 100644
index 000000000..83fae3b88
--- /dev/null
+++ b/accessible/ipc/ProxyAccessible.h
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_a11y_ProxyAccessible_h
+#define mozilla_a11y_ProxyAccessible_h
+
+#include "mozilla/a11y/Role.h"
+#include "nsIAccessibleText.h"
+#include "nsString.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace a11y {
+
+class Attribute;
+class DocAccessibleParent;
+enum class RelationType;
+
+class ProxyAccessible
+{
+public:
+
+ ProxyAccessible(uint64_t aID, ProxyAccessible* aParent,
+ DocAccessibleParent* aDoc, role aRole) :
+ mParent(aParent), mDoc(aDoc), mWrapper(0), mID(aID), mRole(aRole),
+ mOuterDoc(false)
+ {
+ MOZ_COUNT_CTOR(ProxyAccessible);
+ }
+ ~ProxyAccessible()
+ {
+ MOZ_COUNT_DTOR(ProxyAccessible);
+ MOZ_ASSERT(!mWrapper);
+ }
+
+ void AddChildAt(uint32_t aIdx, ProxyAccessible* aChild)
+ { mChildren.InsertElementAt(aIdx, aChild); }
+
+ uint32_t ChildrenCount() const { return mChildren.Length(); }
+ ProxyAccessible* ChildAt(uint32_t aIdx) const { return mChildren[aIdx]; }
+ bool MustPruneChildren() const;
+
+ void Shutdown();
+
+ void SetChildDoc(DocAccessibleParent*);
+
+ /**
+ * Remove The given child.
+ */
+ void RemoveChild(ProxyAccessible* aChild)
+ { mChildren.RemoveElement(aChild); }
+
+ /**
+ * Return the proxy for the parent of the wrapped accessible.
+ */
+ ProxyAccessible* Parent() const { return mParent; }
+
+ /**
+ * Get the role of the accessible we're proxying.
+ */
+ role Role() const { return mRole; }
+
+ /*
+ * Return the states for the proxied accessible.
+ */
+ uint64_t State() const;
+
+ /*
+ * Set aName to the name of the proxied accessible.
+ */
+ void Name(nsString& aName) const;
+
+ /*
+ * Set aValue to the value of the proxied accessible.
+ */
+ void Value(nsString& aValue) const;
+
+ /**
+ * Set aDesc to the description of the proxied accessible.
+ */
+ void Description(nsString& aDesc) const;
+
+ /**
+ * Get the set of attributes on the proxied accessible.
+ */
+ void Attributes(nsTArray<Attribute> *aAttrs) const;
+
+ /**
+ * Return set of targets of given relation type.
+ */
+ nsTArray<ProxyAccessible*> RelationByType(RelationType aType) const;
+
+ /**
+ * Get all relations for this accessible.
+ */
+ void Relations(nsTArray<RelationType>* aTypes,
+ nsTArray<nsTArray<ProxyAccessible*>>* aTargetSets) const;
+
+ /**
+ * Get the text between the given offsets.
+ */
+ void TextSubstring(int32_t aStartOffset, int32_t aEndOfset,
+ nsString& aText) const;
+
+ void GetTextAfterOffset(int32_t aOffset, AccessibleTextBoundary aBoundaryType,
+ nsString& aText, int32_t* aStartOffset,
+ int32_t* aEndOffset);
+
+ void GetTextAtOffset(int32_t aOffset, AccessibleTextBoundary aBoundaryType,
+ nsString& aText, int32_t* aStartOffset,
+ int32_t* aEndOffset);
+
+ void GetTextBeforeOffset(int32_t aOffset, AccessibleTextBoundary aBoundaryType,
+ nsString& aText, int32_t* aStartOffset,
+ int32_t* aEndOffset);
+
+ /**
+ * Allow the platform to store a pointers worth of data on us.
+ */
+ uintptr_t GetWrapper() const { return mWrapper; }
+ void SetWrapper(uintptr_t aWrapper) { mWrapper = aWrapper; }
+
+ /*
+ * Return the ID of the accessible being proxied.
+ */
+ uint64_t ID() const { return mID; }
+
+protected:
+ explicit ProxyAccessible(DocAccessibleParent* aThisAsDoc) :
+ mParent(nullptr), mDoc(aThisAsDoc), mWrapper(0), mID(0),
+ mRole(roles::DOCUMENT)
+ { MOZ_COUNT_CTOR(ProxyAccessible); }
+
+protected:
+ ProxyAccessible* mParent;
+
+private:
+ nsTArray<ProxyAccessible*> mChildren;
+ DocAccessibleParent* mDoc;
+ uintptr_t mWrapper;
+ uint64_t mID;
+ role mRole : 31;
+ bool mOuterDoc : 1;
+};
+
+enum Interfaces
+{
+ HYPERTEXT = 1
+};
+
+}
+}
+
+#endif
diff --git a/accessible/ipc/moz.build b/accessible/ipc/moz.build
new file mode 100644
index 000000000..9fa6ab68a
--- /dev/null
+++ b/accessible/ipc/moz.build
@@ -0,0 +1,33 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+IPDL_SOURCES += ['PDocAccessible.ipdl']
+
+# with --disable-accessibility we need to compile PDocAccessible.ipdl, but not
+# the C++.
+if CONFIG['ACCESSIBILITY']:
+ EXPORTS.mozilla.a11y += [
+ 'DocAccessibleChild.h',
+ 'DocAccessibleParent.h',
+ 'ProxyAccessible.h'
+ ]
+
+ SOURCES += [
+ 'DocAccessibleChild.cpp',
+ 'DocAccessibleParent.cpp',
+ 'ProxyAccessible.cpp'
+ ]
+
+ LOCAL_INCLUDES += [
+ '../base',
+ '../generic',
+ ]
+
+ FINAL_LIBRARY = 'xul'
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FAIL_ON_WARNINGS = True