accessible/src/mac/AccessibleWrap.mm

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:97f4285d439f
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "DocAccessible.h"
7 #include "nsObjCExceptions.h"
8
9 #include "Accessible-inl.h"
10 #include "nsAccUtils.h"
11 #include "Role.h"
12
13 #import "mozAccessible.h"
14 #import "mozActionElements.h"
15 #import "mozHTMLAccessible.h"
16 #import "mozTextAccessible.h"
17
18 using namespace mozilla::a11y;
19
20 AccessibleWrap::
21 AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
22 Accessible(aContent, aDoc), mNativeObject(nil),
23 mNativeInited(false)
24 {
25 }
26
27 AccessibleWrap::~AccessibleWrap()
28 {
29 }
30
31 mozAccessible*
32 AccessibleWrap::GetNativeObject()
33 {
34 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
35
36 if (!mNativeInited && !mNativeObject && !IsDefunct() && !AncestorIsFlat())
37 mNativeObject = [[GetNativeType() alloc] initWithAccessible:this];
38
39 mNativeInited = true;
40
41 return mNativeObject;
42
43 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
44 }
45
46 NS_IMETHODIMP
47 AccessibleWrap::GetNativeInterface (void **aOutInterface)
48 {
49 NS_ENSURE_ARG_POINTER(aOutInterface);
50
51 *aOutInterface = static_cast<void*>(GetNativeObject());
52
53 return *aOutInterface ? NS_OK : NS_ERROR_FAILURE;
54 }
55
56 // overridden in subclasses to create the right kind of object. by default we create a generic
57 // 'mozAccessible' node.
58 Class
59 AccessibleWrap::GetNativeType ()
60 {
61 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
62
63 if (IsXULTabpanels())
64 return [mozPaneAccessible class];
65
66 roles::Role role = Role();
67 switch (role) {
68 case roles::PUSHBUTTON:
69 case roles::SPLITBUTTON:
70 case roles::TOGGLE_BUTTON:
71 {
72 // if this button may show a popup, let's make it of the popupbutton type.
73 return HasPopup() ? [mozPopupButtonAccessible class] :
74 [mozButtonAccessible class];
75 }
76
77 case roles::PAGETAB:
78 return [mozButtonAccessible class];
79
80 case roles::CHECKBUTTON:
81 return [mozCheckboxAccessible class];
82
83 case roles::HEADING:
84 return [mozHeadingAccessible class];
85
86 case roles::PAGETABLIST:
87 return [mozTabsAccessible class];
88
89 case roles::ENTRY:
90 case roles::STATICTEXT:
91 case roles::CAPTION:
92 case roles::ACCEL_LABEL:
93 case roles::PASSWORD_TEXT:
94 // normal textfield (static or editable)
95 return [mozTextAccessible class];
96
97 case roles::TEXT_LEAF:
98 return [mozTextLeafAccessible class];
99
100 case roles::LINK:
101 return [mozLinkAccessible class];
102
103 case roles::COMBOBOX:
104 return [mozPopupButtonAccessible class];
105
106 default:
107 return [mozAccessible class];
108 }
109
110 return nil;
111
112 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
113 }
114
115 // this method is very important. it is fired when an accessible object "dies". after this point
116 // the object might still be around (because some 3rd party still has a ref to it), but it is
117 // in fact 'dead'.
118 void
119 AccessibleWrap::Shutdown ()
120 {
121 // this ensure we will not try to re-create the native object.
122 mNativeInited = true;
123
124 // we really intend to access the member directly.
125 if (mNativeObject) {
126 [mNativeObject expire];
127 [mNativeObject release];
128 mNativeObject = nil;
129 }
130
131 Accessible::Shutdown();
132 }
133
134 nsresult
135 AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
136 {
137 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
138
139 nsresult rv = Accessible::HandleAccEvent(aEvent);
140 NS_ENSURE_SUCCESS(rv, rv);
141
142 uint32_t eventType = aEvent->GetEventType();
143
144 // ignore everything but focus-changed, value-changed, caret and selection
145 // events for now.
146 if (eventType != nsIAccessibleEvent::EVENT_FOCUS &&
147 eventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE &&
148 eventType != nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED &&
149 eventType != nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED)
150 return NS_OK;
151
152 Accessible* accessible = aEvent->GetAccessible();
153 NS_ENSURE_STATE(accessible);
154
155 mozAccessible *nativeAcc = nil;
156 accessible->GetNativeInterface((void**)&nativeAcc);
157 if (!nativeAcc)
158 return NS_ERROR_FAILURE;
159
160 switch (eventType) {
161 case nsIAccessibleEvent::EVENT_FOCUS:
162 [nativeAcc didReceiveFocus];
163 break;
164 case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
165 [nativeAcc valueDidChange];
166 break;
167 case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED:
168 case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED:
169 [nativeAcc selectedTextDidChange];
170 break;
171 }
172
173 return NS_OK;
174
175 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
176 }
177
178 void
179 AccessibleWrap::InvalidateChildren()
180 {
181 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
182
183 [GetNativeObject() invalidateChildren];
184
185 Accessible::InvalidateChildren();
186
187 NS_OBJC_END_TRY_ABORT_BLOCK;
188 }
189
190 bool
191 AccessibleWrap::InsertChildAt(uint32_t aIdx, Accessible* aAccessible)
192 {
193 bool inserted = Accessible::InsertChildAt(aIdx, aAccessible);
194 if (inserted && mNativeObject)
195 [mNativeObject appendChild:aAccessible];
196
197 return inserted;
198 }
199
200 bool
201 AccessibleWrap::RemoveChild(Accessible* aAccessible)
202 {
203 bool removed = Accessible::RemoveChild(aAccessible);
204
205 if (removed && mNativeObject)
206 [mNativeObject invalidateChildren];
207
208 return removed;
209 }
210
211 // if we for some reason have no native accessible, we should be skipped over (and traversed)
212 // when fetching all unignored children, etc. when counting unignored children, we will not be counted.
213 bool
214 AccessibleWrap::IsIgnored()
215 {
216 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
217
218 mozAccessible* nativeObject = GetNativeObject();
219 return (!nativeObject) || [nativeObject accessibilityIsIgnored];
220
221 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
222 }
223
224 void
225 AccessibleWrap::GetUnignoredChildren(nsTArray<Accessible*>* aChildrenArray)
226 {
227 // we're flat; there are no children.
228 if (nsAccUtils::MustPrune(this))
229 return;
230
231 uint32_t childCount = ChildCount();
232 for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
233 AccessibleWrap* childAcc =
234 static_cast<AccessibleWrap*>(GetChildAt(childIdx));
235
236 // If element is ignored, then add its children as substitutes.
237 if (childAcc->IsIgnored()) {
238 childAcc->GetUnignoredChildren(aChildrenArray);
239 continue;
240 }
241
242 aChildrenArray->AppendElement(childAcc);
243 }
244 }
245
246 Accessible*
247 AccessibleWrap::GetUnignoredParent() const
248 {
249 // Go up the chain to find a parent that is not ignored.
250 AccessibleWrap* parentWrap = static_cast<AccessibleWrap*>(Parent());
251 while (parentWrap && parentWrap->IsIgnored())
252 parentWrap = static_cast<AccessibleWrap*>(parentWrap->Parent());
253
254 return parentWrap;
255 }
256
257 ////////////////////////////////////////////////////////////////////////////////
258 // AccessibleWrap protected
259
260 bool
261 AccessibleWrap::AncestorIsFlat()
262 {
263 // We don't create a native object if we're child of a "flat" accessible;
264 // for example, on OS X buttons shouldn't have any children, because that
265 // makes the OS confused.
266 //
267 // To maintain a scripting environment where the XPCOM accessible hierarchy
268 // look the same on all platforms, we still let the C++ objects be created
269 // though.
270
271 Accessible* parent = Parent();
272 while (parent) {
273 if (nsAccUtils::MustPrune(parent))
274 return true;
275
276 parent = parent->Parent();
277 }
278 // no parent was flat
279 return false;
280 }

mercurial