2 /* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "DocAccessibleWrap.h"
9 #include "nsObjCExceptions.h"
10 #include "nsCocoaUtils.h"
11 #include "nsUnicharUtils.h"
13 #include "LocalAccessible-inl.h"
14 #include "nsAccUtils.h"
15 #include "mozilla/a11y/Role.h"
16 #include "TextRange.h"
17 #include "gfxPlatform.h"
19 #import "MOXLandmarkAccessibles.h"
20 #import "MOXMathAccessibles.h"
21 #import "MOXTextMarkerDelegate.h"
22 #import "MOXWebAreaAccessible.h"
23 #import "mozAccessible.h"
24 #import "mozActionElements.h"
25 #import "mozHTMLAccessible.h"
26 #import "mozSelectableElements.h"
27 #import "mozTableAccessible.h"
28 #import "mozTextAccessible.h"
30 using namespace mozilla;
31 using namespace mozilla::a11y;
33 AccessibleWrap::AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc)
34 : LocalAccessible(aContent, aDoc),
36 mNativeInited(false) {
37 if (aContent && aContent->IsElement() && aDoc) {
38 // Check if this accessible is a live region and queue it
39 // it for dispatching an event after it has been inserted.
40 DocAccessibleWrap* doc = static_cast<DocAccessibleWrap*>(aDoc);
41 static const dom::Element::AttrValuesArray sLiveRegionValues[] = {
42 nsGkAtoms::OFF, nsGkAtoms::polite, nsGkAtoms::assertive, nullptr};
43 int32_t attrValue = nsAccUtils::FindARIAAttrValueIn(
44 aContent->AsElement(), nsGkAtoms::aria_live, sLiveRegionValues,
47 // aria-live is "off", do nothing.
48 } else if (attrValue > 0) {
49 // aria-live attribute is polite or assertive. It's live!
50 doc->QueueNewLiveRegion(this);
51 } else if (const nsRoleMapEntry* roleMap =
52 aria::GetRoleMap(aContent->AsElement())) {
53 // aria role defines it as a live region. It's live!
54 if (roleMap->liveAttRule == ePoliteLiveAttr ||
55 roleMap->liveAttRule == eAssertiveLiveAttr) {
56 doc->QueueNewLiveRegion(this);
58 } else if (nsStaticAtom* value = GetAccService()->MarkupAttribute(
59 aContent, nsGkAtoms::aria_live)) {
60 // HTML element defines it as a live region. It's live!
61 if (value == nsGkAtoms::polite || value == nsGkAtoms::assertive) {
62 doc->QueueNewLiveRegion(this);
68 AccessibleWrap::~AccessibleWrap() {}
70 mozAccessible* AccessibleWrap::GetNativeObject() {
71 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
73 if (!mNativeInited && !mNativeObject) {
74 // We don't creat OSX accessibles for xul tooltips, defunct accessibles,
75 // <br> (whitespace) elements, or pruned children.
77 // To maintain a scripting environment where the XPCOM accessible hierarchy
78 // look the same on all platforms, we still let the C++ objects be created
80 if (!IsXULTooltip() && !IsDefunct() && Role() != roles::WHITESPACE) {
81 mNativeObject = [[GetNativeType() alloc] initWithAccessible:this];
89 NS_OBJC_END_TRY_BLOCK_RETURN(nil);
92 void AccessibleWrap::GetNativeInterface(void** aOutInterface) {
93 *aOutInterface = static_cast<void*>(GetNativeObject());
96 // overridden in subclasses to create the right kind of object. by default we
97 // create a generic 'mozAccessible' node.
98 Class AccessibleWrap::GetNativeType() {
99 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
101 if (IsXULTabpanels()) {
102 return [mozPaneAccessible class];
106 return [mozTableAccessible class];
110 return [mozTableRowAccessible class];
114 return [mozTableCellAccessible class];
118 return [MOXWebAreaAccessible class];
121 return GetTypeFromRole(Role());
123 NS_OBJC_END_TRY_BLOCK_RETURN(nil);
126 // this method is very important. it is fired when an accessible object "dies".
127 // after this point the object might still be around (because some 3rd party
128 // still has a ref to it), but it is in fact 'dead'.
129 void AccessibleWrap::Shutdown() {
130 // this ensure we will not try to re-create the native object.
131 mNativeInited = true;
133 // we really intend to access the member directly.
135 [mNativeObject expire];
136 [mNativeObject release];
140 LocalAccessible::Shutdown();
143 nsresult AccessibleWrap::HandleAccEvent(AccEvent* aEvent) {
144 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
146 nsresult rv = LocalAccessible::HandleAccEvent(aEvent);
147 NS_ENSURE_SUCCESS(rv, rv);
150 // The accessible can become defunct after their events are handled.
154 uint32_t eventType = aEvent->GetEventType();
156 if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
157 DocAccessibleWrap* doc = static_cast<DocAccessibleWrap*>(Document());
158 doc->ProcessNewLiveRegions();
163 NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
166 ////////////////////////////////////////////////////////////////////////////////
167 // AccessibleWrap protected
169 Class a11y::GetTypeFromRole(roles::Role aRole) {
170 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
173 case roles::COMBOBOX:
174 return [mozPopupButtonAccessible class];
176 case roles::PUSHBUTTON:
177 return [mozButtonAccessible class];
180 return [mozTabAccessible class];
182 case roles::DATE_EDITOR:
183 return [mozDatePickerAccessible class];
185 case roles::CHECKBUTTON:
186 case roles::TOGGLE_BUTTON:
188 case roles::CHECK_MENU_ITEM:
189 return [mozCheckboxAccessible class];
191 case roles::RADIOBUTTON:
192 case roles::RADIO_MENU_ITEM:
193 return [mozRadioButtonAccessible class];
195 case roles::SPINBUTTON:
197 return [mozIncrementableAccessible class];
200 return [mozHeadingAccessible class];
202 case roles::PAGETABLIST:
203 return [mozTabGroupAccessible class];
207 case roles::EDITCOMBOBOX:
208 case roles::PASSWORD_TEXT:
209 // normal textfield (static or editable)
210 return [mozTextAccessible class];
212 case roles::TEXT_LEAF:
213 case roles::STATICTEXT:
214 return [mozTextLeafAccessible class];
216 case roles::LANDMARK:
217 return [MOXLandmarkAccessible class];
220 return [mozLinkAccessible class];
223 return [mozListboxAccessible class];
225 case roles::LISTITEM:
226 return [MOXListItemAccessible class];
228 case roles::OPTION: {
229 return [mozOptionAccessible class];
232 case roles::RICH_OPTION: {
233 return [mozSelectableChildAccessible class];
236 case roles::COMBOBOX_LIST:
238 case roles::MENUPOPUP: {
239 return [mozMenuAccessible class];
242 case roles::COMBOBOX_OPTION:
243 case roles::PARENT_MENUITEM:
244 case roles::MENUITEM: {
245 return [mozMenuItemAccessible class];
248 case roles::MATHML_ROOT:
249 return [MOXMathRootAccessible class];
251 case roles::MATHML_SQUARE_ROOT:
252 return [MOXMathSquareRootAccessible class];
254 case roles::MATHML_FRACTION:
255 return [MOXMathFractionAccessible class];
257 case roles::MATHML_SUB:
258 case roles::MATHML_SUP:
259 case roles::MATHML_SUB_SUP:
260 return [MOXMathSubSupAccessible class];
262 case roles::MATHML_UNDER:
263 case roles::MATHML_OVER:
264 case roles::MATHML_UNDER_OVER:
265 return [MOXMathUnderOverAccessible class];
268 case roles::TREE_TABLE:
269 return [mozOutlineAccessible class];
271 case roles::OUTLINEITEM:
272 return [mozOutlineRowAccessible class];
275 return [mozAccessible class];
280 NS_OBJC_END_TRY_BLOCK_RETURN(nil);