123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501 |
- /* -*- 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 "DocAccessibleParent.h"
- #include "mozilla/a11y/Platform.h"
- #include "mozilla/dom/TabParent.h"
- #include "xpcAccessibleDocument.h"
- #include "xpcAccEvents.h"
- #include "nsAccUtils.h"
- #include "nsCoreUtils.h"
- namespace mozilla {
- namespace a11y {
- bool
- DocAccessibleParent::RecvShowEvent(const ShowEventData& aData,
- const bool& aFromUser)
- {
- if (mShutdown)
- return true;
- MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
- if (aData.NewTree().IsEmpty()) {
- NS_ERROR("no children being added");
- return false;
- }
- ProxyAccessible* parent = GetAccessible(aData.ID());
- // 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 true;
- }
- uint32_t newChildIdx = aData.Idx();
- if (newChildIdx > parent->ChildrenCount()) {
- NS_ERROR("invalid index to add child at");
- return true;
- }
- uint32_t consumed = AddSubtree(parent, aData.NewTree(), 0, newChildIdx);
- MOZ_ASSERT(consumed == aData.NewTree().Length());
- // XXX This shouldn't happen, but if we failed to add children then the below
- // is pointless and can crash.
- if (!consumed) {
- return true;
- }
- #ifdef DEBUG
- for (uint32_t i = 0; i < consumed; i++) {
- uint64_t id = aData.NewTree()[i].ID();
- MOZ_ASSERT(mAccessibles.GetEntry(id));
- }
- #endif
- MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
- ProxyAccessible* target = parent->ChildAt(newChildIdx);
- ProxyShowHideEvent(target, parent, true, aFromUser);
- if (!nsCoreUtils::AccEventObserversExist()) {
- return true;
- }
- uint32_t type = nsIAccessibleEvent::EVENT_SHOW;
- xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(target);
- xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
- nsIDOMNode* node = nullptr;
- RefPtr<xpcAccEvent> event = new xpcAccEvent(type, xpcAcc, doc, node,
- aFromUser);
- nsCoreUtils::DispatchAccEvent(Move(event));
- return true;
- }
- 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;
- }
- if (mAccessibles.Contains(newChild.ID())) {
- NS_ERROR("ID already in use");
- return 0;
- }
- auto role = static_cast<a11y::role>(newChild.Role());
- ProxyAccessible* newProxy =
- new ProxyAccessible(newChild.ID(), aParent, this, role,
- newChild.Interfaces());
- aParent->AddChildAt(aIdxInParent, newProxy);
- mAccessibles.PutEntry(newChild.ID())->mProxy = newProxy;
- ProxyCreated(newProxy, newChild.Interfaces());
- #if defined(XP_WIN)
- WrapperFor(newProxy)->SetID(newChild.MsaaID());
- #endif
- 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,
- const bool& aFromUser)
- {
- if (mShutdown)
- return true;
- MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
- // We shouldn't actually need this because mAccessibles shouldn't have an
- // entry for the document itself, but it doesn't hurt to be explicit.
- if (!aRootID) {
- NS_ERROR("trying to hide entire document?");
- return false;
- }
- 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();
- ProxyShowHideEvent(root, parent, false, aFromUser);
- RefPtr<xpcAccHideEvent> event = nullptr;
- if (nsCoreUtils::AccEventObserversExist()) {
- uint32_t type = nsIAccessibleEvent::EVENT_HIDE;
- xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(root);
- xpcAccessibleGeneric* xpcParent = GetXPCAccessible(parent);
- ProxyAccessible* next = root->NextSibling();
- xpcAccessibleGeneric* xpcNext = next ? GetXPCAccessible(next) : nullptr;
- ProxyAccessible* prev = root->PrevSibling();
- xpcAccessibleGeneric* xpcPrev = prev ? GetXPCAccessible(prev) : nullptr;
- xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
- nsIDOMNode* node = nullptr;
- event = new xpcAccHideEvent(type, xpcAcc, doc, node, aFromUser, xpcParent,
- xpcNext, xpcPrev);
- }
- parent->RemoveChild(root);
- root->Shutdown();
- MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
- if (event) {
- nsCoreUtils::DispatchAccEvent(Move(event));
- }
- return true;
- }
- bool
- DocAccessibleParent::RecvEvent(const uint64_t& aID, const uint32_t& aEventType)
- {
- ProxyAccessible* proxy = GetAccessible(aID);
- if (!proxy) {
- NS_ERROR("no proxy for event!");
- return true;
- }
- ProxyEvent(proxy, aEventType);
- if (!nsCoreUtils::AccEventObserversExist()) {
- return true;
- }
- xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(proxy);
- xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
- nsIDOMNode* node = nullptr;
- bool fromUser = true; // XXX fix me
- RefPtr<xpcAccEvent> event = new xpcAccEvent(aEventType, xpcAcc, doc, node,
- fromUser);
- nsCoreUtils::DispatchAccEvent(Move(event));
- return true;
- }
- bool
- DocAccessibleParent::RecvStateChangeEvent(const uint64_t& aID,
- const uint64_t& aState,
- const bool& aEnabled)
- {
- ProxyAccessible* target = GetAccessible(aID);
- if (!target) {
- NS_ERROR("we don't know about the target of a state change event!");
- return true;
- }
- ProxyStateChangeEvent(target, aState, aEnabled);
- if (!nsCoreUtils::AccEventObserversExist()) {
- return true;
- }
- xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(target);
- xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
- uint32_t type = nsIAccessibleEvent::EVENT_STATE_CHANGE;
- bool extra;
- uint32_t state = nsAccUtils::To32States(aState, &extra);
- bool fromUser = true; // XXX fix this
- nsIDOMNode* node = nullptr; // XXX can we do better?
- RefPtr<xpcAccStateChangeEvent> event =
- new xpcAccStateChangeEvent(type, xpcAcc, doc, node, fromUser, state, extra,
- aEnabled);
- nsCoreUtils::DispatchAccEvent(Move(event));
- return true;
- }
- bool
- DocAccessibleParent::RecvCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset)
- {
- ProxyAccessible* proxy = GetAccessible(aID);
- if (!proxy) {
- NS_ERROR("unknown caret move event target!");
- return true;
- }
- ProxyCaretMoveEvent(proxy, aOffset);
- if (!nsCoreUtils::AccEventObserversExist()) {
- return true;
- }
- xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(proxy);
- xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
- nsIDOMNode* node = nullptr;
- bool fromUser = true; // XXX fix me
- uint32_t type = nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED;
- RefPtr<xpcAccCaretMoveEvent> event =
- new xpcAccCaretMoveEvent(type, xpcAcc, doc, node, fromUser, aOffset);
- nsCoreUtils::DispatchAccEvent(Move(event));
- return true;
- }
- bool
- DocAccessibleParent::RecvTextChangeEvent(const uint64_t& aID,
- const nsString& aStr,
- const int32_t& aStart,
- const uint32_t& aLen,
- const bool& aIsInsert,
- const bool& aFromUser)
- {
- ProxyAccessible* target = GetAccessible(aID);
- if (!target) {
- NS_ERROR("text change event target is unknown!");
- return true;
- }
- ProxyTextChangeEvent(target, aStr, aStart, aLen, aIsInsert, aFromUser);
- if (!nsCoreUtils::AccEventObserversExist()) {
- return true;
- }
- xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(target);
- xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
- uint32_t type = aIsInsert ? nsIAccessibleEvent::EVENT_TEXT_INSERTED :
- nsIAccessibleEvent::EVENT_TEXT_REMOVED;
- nsIDOMNode* node = nullptr;
- RefPtr<xpcAccTextChangeEvent> event =
- new xpcAccTextChangeEvent(type, xpcAcc, doc, node, aFromUser, aStart, aLen,
- aIsInsert, aStr);
- nsCoreUtils::DispatchAccEvent(Move(event));
- return true;
- }
- bool
- DocAccessibleParent::RecvSelectionEvent(const uint64_t& aID,
- const uint64_t& aWidgetID,
- const uint32_t& aType)
- {
- ProxyAccessible* target = GetAccessible(aID);
- ProxyAccessible* widget = GetAccessible(aWidgetID);
- if (!target || !widget) {
- NS_ERROR("invalid id in selection event");
- return true;
- }
- ProxySelectionEvent(target, widget, aType);
- if (!nsCoreUtils::AccEventObserversExist()) {
- return true;
- }
- xpcAccessibleGeneric* xpcTarget = GetXPCAccessible(target);
- xpcAccessibleDocument* xpcDoc = GetAccService()->GetXPCDocument(this);
- RefPtr<xpcAccEvent> event = new xpcAccEvent(aType, xpcTarget, xpcDoc,
- nullptr, false);
- nsCoreUtils::DispatchAccEvent(Move(event));
- return true;
- }
- bool
- DocAccessibleParent::RecvRoleChangedEvent(const uint32_t& aRole)
- {
- if (aRole >= roles::LAST_ROLE) {
- NS_ERROR("child sent bad role in RoleChangedEvent");
- return false;
- }
- mRole = static_cast<a11y::role>(aRole);
- return true;
- }
- bool
- DocAccessibleParent::RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID)
- {
- // One document should never directly be the child of another.
- // We should always have at least an outer doc accessible in between.
- MOZ_ASSERT(aID);
- if (!aID)
- return false;
- MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
- auto childDoc = static_cast<DocAccessibleParent*>(aChildDoc);
- childDoc->Unbind();
- bool result = AddChildDoc(childDoc, aID, false);
- MOZ_ASSERT(result);
- MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
- return result;
- }
- bool
- DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
- uint64_t aParentID, bool aCreating)
- {
- // We do not use GetAccessible here because we want to be sure to not get the
- // document it self.
- ProxyEntry* e = mAccessibles.GetEntry(aParentID);
- if (!e)
- return false;
- ProxyAccessible* outerDoc = e->mProxy;
- MOZ_ASSERT(outerDoc);
- // OuterDocAccessibles are expected to only have a document as a child.
- // However for compatibility we tolerate replacing one document with another
- // here.
- if (outerDoc->ChildrenCount() > 1 ||
- (outerDoc->ChildrenCount() == 1 && !outerDoc->ChildAt(0)->IsDoc())) {
- return false;
- }
- aChildDoc->mParent = outerDoc;
- outerDoc->SetChildDoc(aChildDoc);
- mChildDocs.AppendElement(aChildDoc);
- aChildDoc->mParentDoc = this;
- if (aCreating) {
- ProxyCreated(aChildDoc, Interfaces::DOCUMENT | Interfaces::HYPERTEXT);
- }
- return true;
- }
- bool
- DocAccessibleParent::RecvShutdown()
- {
- Destroy();
- if (!static_cast<dom::TabParent*>(Manager())->IsDestroyed()) {
- return PDocAccessibleParent::Send__delete__(this);
- }
- return true;
- }
- 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();
- for (auto iter = mAccessibles.Iter(); !iter.Done(); iter.Next()) {
- MOZ_ASSERT(iter.Get()->mProxy != this);
- ProxyDestroyed(iter.Get()->mProxy);
- iter.Remove();
- }
- DocManager::NotifyOfRemoteDocShutdown(this);
- ProxyDestroyed(this);
- if (mParentDoc)
- mParentDoc->RemoveChildDoc(this);
- else if (IsTopLevel())
- GetAccService()->RemoteDocShutdown(this);
- }
- bool
- DocAccessibleParent::CheckDocTree() const
- {
- size_t childDocs = mChildDocs.Length();
- for (size_t i = 0; i < childDocs; i++) {
- if (!mChildDocs[i] || mChildDocs[i]->mParentDoc != this)
- return false;
- if (!mChildDocs[i]->CheckDocTree()) {
- return false;
- }
- }
- return true;
- }
- xpcAccessibleGeneric*
- DocAccessibleParent::GetXPCAccessible(ProxyAccessible* aProxy)
- {
- xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
- MOZ_ASSERT(doc);
- return doc->GetXPCAccessible(aProxy);
- }
- #if defined(XP_WIN)
- /**
- * @param aCOMProxy COM Proxy to the document in the content process.
- */
- void
- DocAccessibleParent::SetCOMProxy(const RefPtr<IAccessible>& aCOMProxy)
- {
- SetCOMInterface(aCOMProxy);
- // Make sure that we're not racing with a tab shutdown
- auto tab = static_cast<dom::TabParent*>(Manager());
- MOZ_ASSERT(tab);
- if (tab->IsDestroyed()) {
- return;
- }
- Accessible* outerDoc = OuterDocOfRemoteBrowser();
- MOZ_ASSERT(outerDoc);
- IAccessible* rawNative = nullptr;
- if (outerDoc) {
- outerDoc->GetNativeInterface((void**) &rawNative);
- MOZ_ASSERT(rawNative);
- }
- IAccessibleHolder::COMPtrType ptr(rawNative);
- IAccessibleHolder holder(Move(ptr));
- Unused << SendParentCOMProxy(holder);
- }
- bool
- DocAccessibleParent::RecvGetWindowedPluginIAccessible(
- const WindowsHandle& aHwnd, IAccessibleHolder* aPluginCOMProxy)
- {
- return false;
- }
- #endif // defined(XP_WIN)
- } // a11y
- } // mozilla
|