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/ProxyAccessibleBase.h" 12 #include "mozilla/a11y/ProxyAccessible.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 ProxyAccessibleBase<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 (!mOuterDoc) { 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 ProxyAccessibleBase<Derived>::SetChildDoc(DocAccessibleParent* aChildDoc) { 52 MOZ_ASSERT(aChildDoc); 53 MOZ_ASSERT(mChildren.Length() == 0); 54 mChildren.AppendElement(aChildDoc); 55 mOuterDoc = true; 56 } 57 58 template <class Derived> ClearChildDoc(DocAccessibleParent * aChildDoc)59void ProxyAccessibleBase<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 ProxyAccessibleBase<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 ProxyAccessibleBase<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* ProxyAccessibleBase<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() const118Accessible* ProxyAccessibleBase<Derived>::OuterDocOfRemoteBrowser() const { 119 auto tab = static_cast<dom::BrowserParent*>(mDoc->Manager()); 120 dom::Element* frame = tab->GetOwnerElement(); 121 NS_ASSERTION(frame, "why isn't the tab in a frame!"); 122 if (!frame) return nullptr; 123 124 DocAccessible* chromeDoc = GetExistingDocAccessible(frame->OwnerDoc()); 125 126 return chromeDoc ? chromeDoc->GetAccessible(frame) : nullptr; 127 } 128 129 template <class Derived> SetParent(Derived * aParent)130void ProxyAccessibleBase<Derived>::SetParent(Derived* aParent) { 131 MOZ_ASSERT(IsDoc(), "we should only reparent documents"); 132 if (!aParent) { 133 mParent = kNoParent; 134 } else { 135 MOZ_ASSERT(!aParent->IsDoc()); 136 mParent = aParent->ID(); 137 } 138 } 139 140 template <class Derived> Parent() const141Derived* ProxyAccessibleBase<Derived>::Parent() const { 142 if (mParent == kNoParent) { 143 return nullptr; 144 } 145 146 // if we are not a document then are parent is another proxy in the same 147 // document. That means we can just ask our document for the proxy with our 148 // parent id. 149 if (!IsDoc()) { 150 return Document()->GetAccessible(mParent); 151 } 152 153 // If we are a top level document then our parent is not a proxy. 154 if (AsDoc()->IsTopLevel()) { 155 return nullptr; 156 } 157 158 // Finally if we are a non top level document then our parent id is for a 159 // proxy in our parent document so get the proxy from there. 160 DocAccessibleParent* parentDoc = AsDoc()->ParentDoc(); 161 MOZ_ASSERT(parentDoc); 162 MOZ_ASSERT(mParent); 163 return parentDoc->GetAccessible(mParent); 164 } 165 166 template class ProxyAccessibleBase<ProxyAccessible>; 167 168 } // namespace a11y 169 } // namespace mozilla 170