diff options
author | Pale Moon <git-repo@palemoon.org> | 2016-09-01 13:39:08 +0200 |
---|---|---|
committer | Pale Moon <git-repo@palemoon.org> | 2016-09-01 13:39:08 +0200 |
commit | 3d8ce1a11a7347cc94a937719c4bc8df46fb8d14 (patch) | |
tree | 8c26ca375a6312751c00a27e1653fb6f189f0463 /accessible/ipc | |
parent | e449bdb1ec3a82f204bffdd9c3c54069d086eee3 (diff) | |
download | palemoon-gre-3d8ce1a11a7347cc94a937719c4bc8df46fb8d14.tar.gz |
Base import of Tycho code (warning: huge commit)
Diffstat (limited to 'accessible/ipc')
-rw-r--r-- | accessible/ipc/DocAccessibleChild.cpp | 280 | ||||
-rw-r--r-- | accessible/ipc/DocAccessibleChild.h | 94 | ||||
-rw-r--r-- | accessible/ipc/DocAccessibleParent.cpp | 181 | ||||
-rw-r--r-- | accessible/ipc/DocAccessibleParent.h | 138 | ||||
-rw-r--r-- | accessible/ipc/PDocAccessible.ipdl | 79 | ||||
-rw-r--r-- | accessible/ipc/ProxyAccessible.cpp | 190 | ||||
-rw-r--r-- | accessible/ipc/ProxyAccessible.h | 157 | ||||
-rw-r--r-- | accessible/ipc/moz.build | 33 |
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 |