Line data Source code
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>
24 : void
25 0 : ProxyAccessibleBase<Derived>::Shutdown()
26 : {
27 0 : MOZ_DIAGNOSTIC_ASSERT(!IsDoc());
28 : xpcAccessibleDocument* xpcDoc =
29 0 : GetAccService()->GetCachedXPCDocument(Document());
30 0 : if (xpcDoc) {
31 0 : xpcDoc->NotifyOfShutdown(static_cast<Derived*>(this));
32 : }
33 :
34 : // XXX Ideally this wouldn't be necessary, but it seems OuterDoc accessibles
35 : // can be destroyed before the doc they own.
36 0 : uint32_t childCount = mChildren.Length();
37 0 : if (!mOuterDoc) {
38 0 : for (uint32_t idx = 0; idx < childCount; idx++)
39 0 : mChildren[idx]->Shutdown();
40 : } else {
41 0 : if (childCount > 1) {
42 0 : MOZ_CRASH("outer doc has too many documents!");
43 0 : } else if (childCount == 1) {
44 0 : mChildren[0]->AsDoc()->Unbind();
45 : }
46 : }
47 :
48 0 : mChildren.Clear();
49 0 : ProxyDestroyed(static_cast<Derived*>(this));
50 0 : mDoc->RemoveAccessible(static_cast<Derived*>(this));
51 0 : }
52 :
53 : template <class Derived>
54 : void
55 0 : ProxyAccessibleBase<Derived>::SetChildDoc(DocAccessibleParent* aChildDoc)
56 : {
57 0 : MOZ_ASSERT(aChildDoc);
58 0 : MOZ_ASSERT(mChildren.Length() == 0);
59 0 : mChildren.AppendElement(aChildDoc);
60 0 : mOuterDoc = true;
61 0 : }
62 :
63 : template <class Derived>
64 : void
65 0 : ProxyAccessibleBase<Derived>::ClearChildDoc(DocAccessibleParent* aChildDoc)
66 : {
67 0 : MOZ_ASSERT(aChildDoc);
68 : // This is possible if we're replacing one document with another: Doc 1
69 : // has not had a chance to remove itself, but was already replaced by Doc 2
70 : // in SetChildDoc(). This could result in two subsequent calls to
71 : // ClearChildDoc() even though mChildren.Length() == 1.
72 0 : MOZ_ASSERT(mChildren.Length() <= 1);
73 0 : mChildren.RemoveElement(aChildDoc);
74 0 : }
75 :
76 : template <class Derived>
77 : bool
78 0 : ProxyAccessibleBase<Derived>::MustPruneChildren() const
79 : {
80 : // this is the equivalent to nsAccUtils::MustPrune for proxies and should be
81 : // kept in sync with that.
82 0 : if (mRole != roles::MENUITEM && mRole != roles::COMBOBOX_OPTION
83 0 : && mRole != roles::OPTION && mRole != roles::ENTRY
84 0 : && mRole != roles::FLAT_EQUATION && mRole != roles::PASSWORD_TEXT
85 0 : && mRole != roles::PUSHBUTTON && mRole != roles::TOGGLE_BUTTON
86 0 : && mRole != roles::GRAPHIC && mRole != roles::SLIDER
87 0 : && mRole != roles::PROGRESSBAR && mRole != roles::SEPARATOR)
88 0 : return false;
89 :
90 0 : if (mChildren.Length() != 1)
91 0 : return false;
92 :
93 0 : return mChildren[0]->Role() == roles::TEXT_LEAF
94 0 : || mChildren[0]->Role() == roles::STATICTEXT;
95 : }
96 :
97 : template <class Derived>
98 : uint32_t
99 0 : ProxyAccessibleBase<Derived>::EmbeddedChildCount() const
100 : {
101 0 : size_t count = 0, kids = mChildren.Length();
102 0 : for (size_t i = 0; i < kids; i++) {
103 0 : if (mChildren[i]->IsEmbeddedObject()) {
104 0 : count++;
105 : }
106 : }
107 :
108 0 : return count;
109 : }
110 :
111 : template <class Derived>
112 : int32_t
113 0 : ProxyAccessibleBase<Derived>::IndexOfEmbeddedChild(const Derived* aChild)
114 : {
115 0 : size_t index = 0, kids = mChildren.Length();
116 0 : for (size_t i = 0; i < kids; i++) {
117 0 : if (mChildren[i]->IsEmbeddedObject()) {
118 0 : if (mChildren[i] == aChild) {
119 0 : return index;
120 : }
121 :
122 0 : index++;
123 : }
124 : }
125 :
126 0 : return -1;
127 : }
128 :
129 : template <class Derived>
130 : Derived*
131 0 : ProxyAccessibleBase<Derived>::EmbeddedChildAt(size_t aChildIdx)
132 : {
133 0 : size_t index = 0, kids = mChildren.Length();
134 0 : for (size_t i = 0; i < kids; i++) {
135 0 : if (!mChildren[i]->IsEmbeddedObject()) {
136 0 : continue;
137 : }
138 :
139 0 : if (index == aChildIdx) {
140 0 : return mChildren[i];
141 : }
142 :
143 0 : index++;
144 : }
145 :
146 0 : return nullptr;
147 : }
148 :
149 : template <class Derived>
150 : Accessible*
151 0 : ProxyAccessibleBase<Derived>::OuterDocOfRemoteBrowser() const
152 : {
153 0 : auto tab = static_cast<dom::TabParent*>(mDoc->Manager());
154 0 : dom::Element* frame = tab->GetOwnerElement();
155 0 : NS_ASSERTION(frame, "why isn't the tab in a frame!");
156 0 : if (!frame)
157 0 : return nullptr;
158 :
159 0 : DocAccessible* chromeDoc = GetExistingDocAccessible(frame->OwnerDoc());
160 :
161 0 : return chromeDoc ? chromeDoc->GetAccessible(frame) : nullptr;
162 : }
163 :
164 : template<class Derived>
165 : void
166 0 : ProxyAccessibleBase<Derived>::SetParent(Derived* aParent)
167 : {
168 0 : MOZ_ASSERT(IsDoc(), "we should only reparent documents");
169 0 : if (!aParent) {
170 0 : mParent = kNoParent;
171 : } else {
172 0 : MOZ_ASSERT(!aParent->IsDoc());
173 0 : mParent = aParent->ID();
174 : }
175 0 : }
176 :
177 : template<class Derived>
178 : Derived*
179 0 : ProxyAccessibleBase<Derived>::Parent() const
180 : {
181 0 : if (mParent == kNoParent) {
182 0 : return nullptr;
183 : }
184 :
185 : // if we are not a document then are parent is another proxy in the same
186 : // document. That means we can just ask our document for the proxy with our
187 : // parent id.
188 0 : if (!IsDoc()) {
189 0 : return Document()->GetAccessible(mParent);
190 : }
191 :
192 : // If we are a top level document then our parent is not a proxy.
193 0 : if (AsDoc()->IsTopLevel()) {
194 0 : return nullptr;
195 : }
196 :
197 : // Finally if we are a non top level document then our parent id is for a
198 : // proxy in our parent document so get the proxy from there.
199 0 : DocAccessibleParent* parentDoc = AsDoc()->ParentDoc();
200 0 : MOZ_ASSERT(parentDoc);
201 0 : MOZ_ASSERT(mParent);
202 0 : return parentDoc->GetAccessible(mParent);
203 : }
204 :
205 : template class ProxyAccessibleBase<ProxyAccessible>;
206 :
207 : } // namespace a11y
208 : } // namespace mozilla
|