1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "DocAccessible.h" 8 #include "mozilla/a11y/DocAccessibleParent.h" 9 #include "mozilla/a11y/DocManager.h" 10 #include "mozilla/a11y/Platform.h" 11 #include "mozilla/a11y/RemoteAccessibleBase.h" 12 #include "mozilla/a11y/RemoteAccessible.h" 13 #include "mozilla/a11y/Role.h" 14 #include "mozilla/dom/Element.h" 15 #include "mozilla/dom/BrowserParent.h" 16 #include "mozilla/Unused.h" 17 #include "RelationType.h" 18 #include "xpcAccessibleDocument.h" 19 20 namespace mozilla { 21 namespace a11y { 22 23 template <class Derived> Shutdown()24void RemoteAccessibleBase<Derived>::Shutdown() { 25 MOZ_DIAGNOSTIC_ASSERT(!IsDoc()); 26 xpcAccessibleDocument* xpcDoc = 27 GetAccService()->GetCachedXPCDocument(Document()); 28 if (xpcDoc) { 29 xpcDoc->NotifyOfShutdown(static_cast<Derived*>(this)); 30 } 31 32 // XXX Ideally this wouldn't be necessary, but it seems OuterDoc accessibles 33 // can be destroyed before the doc they own. 34 uint32_t childCount = mChildren.Length(); 35 if (!IsOuterDoc()) { 36 for (uint32_t idx = 0; idx < childCount; idx++) mChildren[idx]->Shutdown(); 37 } else { 38 if (childCount > 1) { 39 MOZ_CRASH("outer doc has too many documents!"); 40 } else if (childCount == 1) { 41 mChildren[0]->AsDoc()->Unbind(); 42 } 43 } 44 45 mChildren.Clear(); 46 ProxyDestroyed(static_cast<Derived*>(this)); 47 mDoc->RemoveAccessible(static_cast<Derived*>(this)); 48 } 49 50 template <class Derived> SetChildDoc(DocAccessibleParent * aChildDoc)51void RemoteAccessibleBase<Derived>::SetChildDoc( 52 DocAccessibleParent* aChildDoc) { 53 MOZ_ASSERT(aChildDoc); 54 MOZ_ASSERT(mChildren.Length() == 0); 55 mChildren.AppendElement(aChildDoc); 56 } 57 58 template <class Derived> ClearChildDoc(DocAccessibleParent * aChildDoc)59void RemoteAccessibleBase<Derived>::ClearChildDoc( 60 DocAccessibleParent* aChildDoc) { 61 MOZ_ASSERT(aChildDoc); 62 // This is possible if we're replacing one document with another: Doc 1 63 // has not had a chance to remove itself, but was already replaced by Doc 2 64 // in SetChildDoc(). This could result in two subsequent calls to 65 // ClearChildDoc() even though mChildren.Length() == 1. 66 MOZ_ASSERT(mChildren.Length() <= 1); 67 mChildren.RemoveElement(aChildDoc); 68 } 69 70 template <class Derived> EmbeddedChildCount() const71uint32_t RemoteAccessibleBase<Derived>::EmbeddedChildCount() const { 72 size_t count = 0, kids = mChildren.Length(); 73 for (size_t i = 0; i < kids; i++) { 74 if (mChildren[i]->IsEmbeddedObject()) { 75 count++; 76 } 77 } 78 79 return count; 80 } 81 82 template <class Derived> IndexOfEmbeddedChild(const Derived * aChild)83int32_t RemoteAccessibleBase<Derived>::IndexOfEmbeddedChild( 84 const Derived* aChild) { 85 size_t index = 0, kids = mChildren.Length(); 86 for (size_t i = 0; i < kids; i++) { 87 if (mChildren[i]->IsEmbeddedObject()) { 88 if (mChildren[i] == aChild) { 89 return index; 90 } 91 92 index++; 93 } 94 } 95 96 return -1; 97 } 98 99 template <class Derived> EmbeddedChildAt(size_t aChildIdx)100Derived* RemoteAccessibleBase<Derived>::EmbeddedChildAt(size_t aChildIdx) { 101 size_t index = 0, kids = mChildren.Length(); 102 for (size_t i = 0; i < kids; i++) { 103 if (!mChildren[i]->IsEmbeddedObject()) { 104 continue; 105 } 106 107 if (index == aChildIdx) { 108 return mChildren[i]; 109 } 110 111 index++; 112 } 113 114 return nullptr; 115 } 116 117 template <class Derived> OuterDocOfRemoteBrowser() const118LocalAccessible* RemoteAccessibleBase<Derived>::OuterDocOfRemoteBrowser() 119 const { 120 auto tab = static_cast<dom::BrowserParent*>(mDoc->Manager()); 121 dom::Element* frame = tab->GetOwnerElement(); 122 NS_ASSERTION(frame, "why isn't the tab in a frame!"); 123 if (!frame) return nullptr; 124 125 DocAccessible* chromeDoc = GetExistingDocAccessible(frame->OwnerDoc()); 126 127 return chromeDoc ? chromeDoc->GetAccessible(frame) : nullptr; 128 } 129 130 template <class Derived> SetParent(Derived * aParent)131void RemoteAccessibleBase<Derived>::SetParent(Derived* aParent) { 132 MOZ_ASSERT(IsDoc(), "we should only reparent documents"); 133 if (!aParent) { 134 mParent = kNoParent; 135 } else { 136 MOZ_ASSERT(!aParent->IsDoc()); 137 mParent = aParent->ID(); 138 } 139 } 140 141 template <class Derived> RemoteParent() const142Derived* RemoteAccessibleBase<Derived>::RemoteParent() const { 143 if (mParent == kNoParent) { 144 return nullptr; 145 } 146 147 // if we are not a document then are parent is another proxy in the same 148 // document. That means we can just ask our document for the proxy with our 149 // parent id. 150 if (!IsDoc()) { 151 return Document()->GetAccessible(mParent); 152 } 153 154 // If we are a top level document then our parent is not a proxy. 155 if (AsDoc()->IsTopLevel()) { 156 return nullptr; 157 } 158 159 // Finally if we are a non top level document then our parent id is for a 160 // proxy in our parent document so get the proxy from there. 161 DocAccessibleParent* parentDoc = AsDoc()->ParentDoc(); 162 MOZ_ASSERT(parentDoc); 163 MOZ_ASSERT(mParent); 164 return parentDoc->GetAccessible(mParent); 165 } 166 167 template class RemoteAccessibleBase<RemoteAccessible>; 168 169 } // namespace a11y 170 } // namespace mozilla 171