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/TabParent.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> MustPruneChildren() const71bool ProxyAccessibleBase<Derived>::MustPruneChildren() const { 72 // this is the equivalent to nsAccUtils::MustPrune for proxies and should be 73 // kept in sync with that. 74 if (mRole != roles::MENUITEM && mRole != roles::COMBOBOX_OPTION && 75 mRole != roles::OPTION && mRole != roles::ENTRY && 76 mRole != roles::FLAT_EQUATION && mRole != roles::PASSWORD_TEXT && 77 mRole != roles::PUSHBUTTON && mRole != roles::TOGGLE_BUTTON && 78 mRole != roles::GRAPHIC && mRole != roles::SLIDER && 79 mRole != roles::PROGRESSBAR && mRole != roles::SEPARATOR) 80 return false; 81 82 if (mChildren.Length() != 1) return false; 83 84 return mChildren[0]->Role() == roles::TEXT_LEAF || 85 mChildren[0]->Role() == roles::STATICTEXT; 86 } 87 88 template <class Derived> EmbeddedChildCount() const89uint32_t ProxyAccessibleBase<Derived>::EmbeddedChildCount() const { 90 size_t count = 0, kids = mChildren.Length(); 91 for (size_t i = 0; i < kids; i++) { 92 if (mChildren[i]->IsEmbeddedObject()) { 93 count++; 94 } 95 } 96 97 return count; 98 } 99 100 template <class Derived> IndexOfEmbeddedChild(const Derived * aChild)101int32_t ProxyAccessibleBase<Derived>::IndexOfEmbeddedChild( 102 const Derived* aChild) { 103 size_t index = 0, kids = mChildren.Length(); 104 for (size_t i = 0; i < kids; i++) { 105 if (mChildren[i]->IsEmbeddedObject()) { 106 if (mChildren[i] == aChild) { 107 return index; 108 } 109 110 index++; 111 } 112 } 113 114 return -1; 115 } 116 117 template <class Derived> EmbeddedChildAt(size_t aChildIdx)118Derived* ProxyAccessibleBase<Derived>::EmbeddedChildAt(size_t aChildIdx) { 119 size_t index = 0, kids = mChildren.Length(); 120 for (size_t i = 0; i < kids; i++) { 121 if (!mChildren[i]->IsEmbeddedObject()) { 122 continue; 123 } 124 125 if (index == aChildIdx) { 126 return mChildren[i]; 127 } 128 129 index++; 130 } 131 132 return nullptr; 133 } 134 135 template <class Derived> OuterDocOfRemoteBrowser() const136Accessible* ProxyAccessibleBase<Derived>::OuterDocOfRemoteBrowser() const { 137 auto tab = static_cast<dom::TabParent*>(mDoc->Manager()); 138 dom::Element* frame = tab->GetOwnerElement(); 139 NS_ASSERTION(frame, "why isn't the tab in a frame!"); 140 if (!frame) return nullptr; 141 142 DocAccessible* chromeDoc = GetExistingDocAccessible(frame->OwnerDoc()); 143 144 return chromeDoc ? chromeDoc->GetAccessible(frame) : nullptr; 145 } 146 147 template <class Derived> SetParent(Derived * aParent)148void ProxyAccessibleBase<Derived>::SetParent(Derived* aParent) { 149 MOZ_ASSERT(IsDoc(), "we should only reparent documents"); 150 if (!aParent) { 151 mParent = kNoParent; 152 } else { 153 MOZ_ASSERT(!aParent->IsDoc()); 154 mParent = aParent->ID(); 155 } 156 } 157 158 template <class Derived> Parent() const159Derived* ProxyAccessibleBase<Derived>::Parent() const { 160 if (mParent == kNoParent) { 161 return nullptr; 162 } 163 164 // if we are not a document then are parent is another proxy in the same 165 // document. That means we can just ask our document for the proxy with our 166 // parent id. 167 if (!IsDoc()) { 168 return Document()->GetAccessible(mParent); 169 } 170 171 // If we are a top level document then our parent is not a proxy. 172 if (AsDoc()->IsTopLevel()) { 173 return nullptr; 174 } 175 176 // Finally if we are a non top level document then our parent id is for a 177 // proxy in our parent document so get the proxy from there. 178 DocAccessibleParent* parentDoc = AsDoc()->ParentDoc(); 179 MOZ_ASSERT(parentDoc); 180 MOZ_ASSERT(mParent); 181 return parentDoc->GetAccessible(mParent); 182 } 183 184 template class ProxyAccessibleBase<ProxyAccessible>; 185 186 } // namespace a11y 187 } // namespace mozilla 188