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/. */
6 #include "nsAccessibilityService.h"
8 // NOTE: alphabetically ordered
9 #include "ApplicationAccessibleWrap.h"
10 #include "ARIAGridAccessibleWrap.h"
12 #include "DocAccessible-inl.h"
13 #include "FocusManager.h"
14 #include "HTMLCanvasAccessible.h"
15 #include "HTMLElementAccessibles.h"
16 #include "HTMLImageMapAccessible.h"
17 #include "HTMLLinkAccessible.h"
18 #include "HTMLListAccessible.h"
19 #include "HTMLSelectAccessible.h"
20 #include "HTMLTableAccessibleWrap.h"
21 #include "HyperTextAccessibleWrap.h"
22 #include "RootAccessible.h"
23 #include "nsAccessiblePivot.h"
24 #include "nsAccUtils.h"
25 #include "nsAttrName.h"
26 #include "nsEventShell.h"
28 #include "OuterDocAccessible.h"
31 #ifdef MOZ_ACCESSIBILITY_ATK
32 #include "RootAccessibleWrap.h"
35 #include "Statistics.h"
36 #include "TextLeafAccessibleWrap.h"
38 #ifdef MOZ_ACCESSIBILITY_ATK
39 #include "AtkSocketAccessible.h"
43 #include "mozilla/a11y/Compatibility.h"
44 #include "HTMLWin32ObjectAccessible.h"
45 #include "mozilla/StaticPtr.h"
52 #ifdef MOZ_CRASHREPORTER
53 #include "nsExceptionHandler.h"
56 #include "nsImageFrame.h"
57 #include "nsIObserverService.h"
58 #include "nsLayoutUtils.h"
59 #include "nsObjectFrame.h"
60 #include "nsSVGPathGeometryFrame.h"
61 #include "nsTreeBodyFrame.h"
62 #include "nsTreeColumns.h"
63 #include "nsTreeUtils.h"
64 #include "nsXBLPrototypeBinding.h"
65 #include "nsXBLBinding.h"
66 #include "mozilla/ArrayUtils.h"
67 #include "mozilla/dom/DOMStringList.h"
68 #include "mozilla/Preferences.h"
69 #include "mozilla/Services.h"
70 #include "nsDeckFrame.h"
73 #include "XULAlertAccessible.h"
74 #include "XULColorPickerAccessible.h"
75 #include "XULComboboxAccessible.h"
76 #include "XULElementAccessibles.h"
77 #include "XULFormControlAccessible.h"
78 #include "XULListboxAccessibleWrap.h"
79 #include "XULMenuAccessibleWrap.h"
80 #include "XULSliderAccessible.h"
81 #include "XULTabAccessible.h"
82 #include "XULTreeGridAccessibleWrap.h"
85 #if defined(XP_WIN) || defined(MOZ_ACCESSIBILITY_ATK)
86 #include "nsNPAPIPluginInstance.h"
89 using namespace mozilla
;
90 using namespace mozilla::a11y
;
91 using namespace mozilla::dom
;
93 ////////////////////////////////////////////////////////////////////////////////
95 ////////////////////////////////////////////////////////////////////////////////
98 * Return true if the element must be accessible.
101 MustBeAccessible(nsIContent
* aContent
, DocAccessible
* aDocument
)
103 if (aContent
->GetPrimaryFrame()->IsFocusable())
106 uint32_t attrCount
= aContent
->GetAttrCount();
107 for (uint32_t attrIdx
= 0; attrIdx
< attrCount
; attrIdx
++) {
108 const nsAttrName
* attr
= aContent
->GetAttrNameAt(attrIdx
);
109 if (attr
->NamespaceEquals(kNameSpaceID_None
)) {
110 nsIAtom
* attrAtom
= attr
->Atom();
111 nsDependentAtomString
attrStr(attrAtom
);
112 if (!StringBeginsWith(attrStr
, NS_LITERAL_STRING("aria-")))
113 continue; // not ARIA
115 // A global state or a property and in case of token defined.
116 uint8_t attrFlags
= aria::AttrCharacteristicsFor(attrAtom
);
117 if ((attrFlags
& ATTR_GLOBAL
) && (!(attrFlags
& ATTR_VALTOKEN
) ||
118 nsAccUtils::HasDefinedARIAToken(aContent
, attrAtom
))) {
124 // If the given ID is referred by relation attribute then create an accessible
127 if (nsCoreUtils::GetID(aContent
, id
) && !id
.IsEmpty())
128 return aDocument
->IsDependentID(id
);
133 ////////////////////////////////////////////////////////////////////////////////
134 // nsAccessibilityService
135 ////////////////////////////////////////////////////////////////////////////////
137 nsAccessibilityService
*nsAccessibilityService::gAccessibilityService
= nullptr;
138 ApplicationAccessible
* nsAccessibilityService::gApplicationAccessible
= nullptr;
139 bool nsAccessibilityService::gIsShutdown
= true;
141 nsAccessibilityService::nsAccessibilityService() :
142 DocManager(), FocusManager()
146 nsAccessibilityService::~nsAccessibilityService()
148 NS_ASSERTION(gIsShutdown
, "Accessibility wasn't shutdown!");
149 gAccessibilityService
= nullptr;
152 ////////////////////////////////////////////////////////////////////////////////
155 NS_IMPL_ISUPPORTS_INHERITED(nsAccessibilityService
,
157 nsIAccessibilityService
,
158 nsIAccessibleRetrieval
,
160 nsISelectionListener
) // from SelectionManager
162 ////////////////////////////////////////////////////////////////////////////////
166 nsAccessibilityService::Observe(nsISupports
*aSubject
, const char *aTopic
,
167 const char16_t
*aData
)
169 if (!nsCRT::strcmp(aTopic
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
))
175 // nsIAccessibilityService
177 nsAccessibilityService::NotifyOfAnchorJumpTo(nsIContent
* aTargetNode
)
179 nsIDocument
* documentNode
= aTargetNode
->GetCurrentDoc();
181 DocAccessible
* document
= GetDocAccessible(documentNode
);
183 document
->SetAnchorJump(aTargetNode
);
187 // nsIAccessibilityService
189 nsAccessibilityService::FireAccessibleEvent(uint32_t aEvent
,
192 nsEventShell::FireEvent(aEvent
, aTarget
);
195 ////////////////////////////////////////////////////////////////////////////////
196 // nsIAccessibilityService
199 nsAccessibilityService::GetRootDocumentAccessible(nsIPresShell
* aPresShell
,
202 nsIPresShell
* ps
= aPresShell
;
203 nsIDocument
* documentNode
= aPresShell
->GetDocument();
205 nsCOMPtr
<nsIDocShellTreeItem
> treeItem(documentNode
->GetDocShell());
207 nsCOMPtr
<nsIDocShellTreeItem
> rootTreeItem
;
208 treeItem
->GetRootTreeItem(getter_AddRefs(rootTreeItem
));
209 if (treeItem
!= rootTreeItem
) {
210 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(rootTreeItem
));
211 ps
= docShell
->GetPresShell();
214 return aCanCreate
? GetDocAccessible(ps
) : ps
->GetDocAccessible();
221 static StaticAutoPtr
<nsTArray
<nsCOMPtr
<nsIContent
> > > sPendingPlugins
;
222 static StaticAutoPtr
<nsTArray
<nsCOMPtr
<nsITimer
> > > sPluginTimers
;
224 class PluginTimerCallBack MOZ_FINAL
: public nsITimerCallback
226 ~PluginTimerCallBack() {}
229 PluginTimerCallBack(nsIContent
* aContent
) : mContent(aContent
) {}
233 NS_IMETHODIMP
Notify(nsITimer
* aTimer
) MOZ_FINAL
235 if (!mContent
->IsInDoc())
238 nsIPresShell
* ps
= mContent
->OwnerDoc()->GetShell();
240 DocAccessible
* doc
= ps
->GetDocAccessible();
242 // Make sure that if we created an accessible for the plugin that wasn't
243 // a plugin accessible we remove it before creating the right accessible.
244 doc
->RecreateAccessible(mContent
);
245 sPluginTimers
->RemoveElement(aTimer
);
250 // We couldn't get a doc accessible so presumably the document went away.
251 // In this case don't leak our ref to the content or timer.
252 sPendingPlugins
->RemoveElement(mContent
);
253 sPluginTimers
->RemoveElement(aTimer
);
258 nsCOMPtr
<nsIContent
> mContent
;
261 NS_IMPL_ISUPPORTS(PluginTimerCallBack
, nsITimerCallback
)
264 already_AddRefed
<Accessible
>
265 nsAccessibilityService::CreatePluginAccessible(nsObjectFrame
* aFrame
,
266 nsIContent
* aContent
,
267 Accessible
* aContext
)
269 // nsObjectFrame means a plugin, so we need to use the accessibility support
271 if (aFrame
->GetRect().IsEmpty())
274 #if defined(XP_WIN) || defined(MOZ_ACCESSIBILITY_ATK)
275 nsRefPtr
<nsNPAPIPluginInstance
> pluginInstance
;
276 if (NS_SUCCEEDED(aFrame
->GetPluginInstance(getter_AddRefs(pluginInstance
))) &&
279 if (!sPendingPlugins
->Contains(aContent
) &&
280 (Preferences::GetBool("accessibility.delay_plugins") ||
281 Compatibility::IsJAWS() || Compatibility::IsWE())) {
282 nsCOMPtr
<nsITimer
> timer
= do_CreateInstance(NS_TIMER_CONTRACTID
);
283 nsRefPtr
<PluginTimerCallBack
> cb
= new PluginTimerCallBack(aContent
);
284 timer
->InitWithCallback(cb
, Preferences::GetUint("accessibility.delay_plugin_time"),
285 nsITimer::TYPE_ONE_SHOT
);
286 sPluginTimers
->AppendElement(timer
);
287 sPendingPlugins
->AppendElement(aContent
);
291 // We need to remove aContent from the pending plugins here to avoid
292 // reentrancy. When the timer fires it calls
293 // DocAccessible::ContentInserted() which does the work async.
294 sPendingPlugins
->RemoveElement(aContent
);
296 // Note: pluginPort will be null if windowless.
297 HWND pluginPort
= nullptr;
298 aFrame
->GetPluginPort(&pluginPort
);
300 nsRefPtr
<Accessible
> accessible
=
301 new HTMLWin32ObjectOwnerAccessible(aContent
, aContext
->Document(),
303 return accessible
.forget();
305 #elif MOZ_ACCESSIBILITY_ATK
306 if (!AtkSocketAccessible::gCanEmbed
)
309 // Note this calls into the plugin, so crazy things may happen and aFrame
312 nsresult rv
= pluginInstance
->GetValueFromPlugin(
313 NPPVpluginNativeAccessibleAtkPlugId
, &plugId
);
314 if (NS_SUCCEEDED(rv
) && !plugId
.IsEmpty()) {
315 nsRefPtr
<AtkSocketAccessible
> socketAccessible
=
316 new AtkSocketAccessible(aContent
, aContext
->Document(), plugId
);
318 return socketAccessible
.forget();
328 nsAccessibilityService::DeckPanelSwitched(nsIPresShell
* aPresShell
,
329 nsIContent
* aDeckNode
,
330 nsIFrame
* aPrevBoxFrame
,
331 nsIFrame
* aCurrentBoxFrame
)
333 // Ignore tabpanels elements (a deck having an accessible) since their
334 // children are accessible not depending on selected tab.
335 DocAccessible
* document
= GetDocAccessible(aPresShell
);
336 if (!document
|| document
->HasAccessible(aDeckNode
))
340 nsIContent
* panelNode
= aPrevBoxFrame
->GetContent();
342 if (logging::IsEnabled(logging::eTree
)) {
343 logging::MsgBegin("TREE", "deck panel unselected");
344 logging::Node("container", panelNode
);
345 logging::Node("content", aDeckNode
);
350 document
->ContentRemoved(aDeckNode
, panelNode
);
353 if (aCurrentBoxFrame
) {
354 nsIContent
* panelNode
= aCurrentBoxFrame
->GetContent();
356 if (logging::IsEnabled(logging::eTree
)) {
357 logging::MsgBegin("TREE", "deck panel selected");
358 logging::Node("container", panelNode
);
359 logging::Node("content", aDeckNode
);
364 document
->ContentInserted(aDeckNode
, panelNode
, panelNode
->GetNextSibling());
369 nsAccessibilityService::ContentRangeInserted(nsIPresShell
* aPresShell
,
370 nsIContent
* aContainer
,
371 nsIContent
* aStartChild
,
372 nsIContent
* aEndChild
)
375 if (logging::IsEnabled(logging::eTree
)) {
376 logging::MsgBegin("TREE", "content inserted");
377 logging::Node("container", aContainer
);
378 for (nsIContent
* child
= aStartChild
; child
!= aEndChild
;
379 child
= child
->GetNextSibling()) {
380 logging::Node("content", child
);
387 DocAccessible
* docAccessible
= GetDocAccessible(aPresShell
);
389 docAccessible
->ContentInserted(aContainer
, aStartChild
, aEndChild
);
393 nsAccessibilityService::ContentRemoved(nsIPresShell
* aPresShell
,
394 nsIContent
* aContainer
,
398 if (logging::IsEnabled(logging::eTree
)) {
399 logging::MsgBegin("TREE", "content removed");
400 logging::Node("container", aContainer
);
401 logging::Node("content", aChild
);
407 DocAccessible
* docAccessible
= GetDocAccessible(aPresShell
);
409 docAccessible
->ContentRemoved(aContainer
, aChild
);
413 nsAccessibilityService::UpdateText(nsIPresShell
* aPresShell
,
414 nsIContent
* aContent
)
416 DocAccessible
* document
= GetDocAccessible(aPresShell
);
418 document
->UpdateText(aContent
);
422 nsAccessibilityService::TreeViewChanged(nsIPresShell
* aPresShell
,
423 nsIContent
* aContent
,
426 DocAccessible
* document
= GetDocAccessible(aPresShell
);
428 Accessible
* accessible
= document
->GetAccessible(aContent
);
430 XULTreeAccessible
* treeAcc
= accessible
->AsXULTree();
432 treeAcc
->TreeViewChanged(aView
);
438 nsAccessibilityService::RangeValueChanged(nsIPresShell
* aPresShell
,
439 nsIContent
* aContent
)
441 DocAccessible
* document
= GetDocAccessible(aPresShell
);
443 Accessible
* accessible
= document
->GetAccessible(aContent
);
445 document
->FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE
,
452 nsAccessibilityService::UpdateListBullet(nsIPresShell
* aPresShell
,
453 nsIContent
* aHTMLListItemContent
,
456 DocAccessible
* document
= GetDocAccessible(aPresShell
);
458 Accessible
* accessible
= document
->GetAccessible(aHTMLListItemContent
);
460 HTMLLIAccessible
* listItem
= accessible
->AsHTMLListItem();
462 listItem
->UpdateBullet(aHasBullet
);
468 nsAccessibilityService::UpdateImageMap(nsImageFrame
* aImageFrame
)
470 nsIPresShell
* presShell
= aImageFrame
->PresContext()->PresShell();
471 DocAccessible
* document
= GetDocAccessible(presShell
);
473 Accessible
* accessible
=
474 document
->GetAccessible(aImageFrame
->GetContent());
476 HTMLImageMapAccessible
* imageMap
= accessible
->AsImageMap();
478 imageMap
->UpdateChildAreas();
482 // If image map was initialized after we created an accessible (that'll
483 // be an image accessible) then recreate it.
484 RecreateAccessible(presShell
, aImageFrame
->GetContent());
490 nsAccessibilityService::UpdateLabelValue(nsIPresShell
* aPresShell
,
491 nsIContent
* aLabelElm
,
492 const nsString
& aNewValue
)
494 DocAccessible
* document
= GetDocAccessible(aPresShell
);
496 Accessible
* accessible
= document
->GetAccessible(aLabelElm
);
498 XULLabelAccessible
* xulLabel
= accessible
->AsXULLabel();
499 NS_ASSERTION(xulLabel
,
500 "UpdateLabelValue was called for wrong accessible!");
502 xulLabel
->UpdateLabelValue(aNewValue
);
508 nsAccessibilityService::PresShellActivated(nsIPresShell
* aPresShell
)
510 DocAccessible
* document
= aPresShell
->GetDocAccessible();
512 RootAccessible
* rootDocument
= document
->RootAccessible();
513 NS_ASSERTION(rootDocument
, "Entirely broken tree: no root document!");
515 rootDocument
->DocumentActivated(document
);
520 nsAccessibilityService::RecreateAccessible(nsIPresShell
* aPresShell
,
521 nsIContent
* aContent
)
523 DocAccessible
* document
= GetDocAccessible(aPresShell
);
525 document
->RecreateAccessible(aContent
);
528 ////////////////////////////////////////////////////////////////////////////////
529 // nsIAccessibleRetrieval
532 nsAccessibilityService::GetApplicationAccessible(nsIAccessible
** aAccessibleApplication
)
534 NS_ENSURE_ARG_POINTER(aAccessibleApplication
);
536 NS_IF_ADDREF(*aAccessibleApplication
= ApplicationAcc());
542 nsAccessibilityService::GetAccessibleFor(nsIDOMNode
*aNode
,
543 nsIAccessible
**aAccessible
)
545 NS_ENSURE_ARG_POINTER(aAccessible
);
546 *aAccessible
= nullptr;
550 nsCOMPtr
<nsINode
> node(do_QueryInterface(aNode
));
552 return NS_ERROR_INVALID_ARG
;
554 DocAccessible
* document
= GetDocAccessible(node
->OwnerDoc());
556 NS_IF_ADDREF(*aAccessible
= document
->GetAccessible(node
));
562 nsAccessibilityService::GetStringRole(uint32_t aRole
, nsAString
& aString
)
564 #define ROLE(geckoRole, stringRole, atkRole, \
565 macRole, msaaRole, ia2Role, nameRule) \
566 case roles::geckoRole: \
567 CopyUTF8toUTF16(stringRole, aString); \
573 aString
.AssignLiteral("unknown");
581 nsAccessibilityService::GetStringStates(uint32_t aState
, uint32_t aExtraState
,
582 nsISupports
**aStringStates
)
584 nsRefPtr
<DOMStringList
> stringStates
= new DOMStringList();
586 uint64_t state
= nsAccUtils::To64State(aState
, aExtraState
);
589 if (state
& states::UNAVAILABLE
)
590 stringStates
->Add(NS_LITERAL_STRING("unavailable"));
591 if (state
& states::SELECTED
)
592 stringStates
->Add(NS_LITERAL_STRING("selected"));
593 if (state
& states::FOCUSED
)
594 stringStates
->Add(NS_LITERAL_STRING("focused"));
595 if (state
& states::PRESSED
)
596 stringStates
->Add(NS_LITERAL_STRING("pressed"));
597 if (state
& states::CHECKED
)
598 stringStates
->Add(NS_LITERAL_STRING("checked"));
599 if (state
& states::MIXED
)
600 stringStates
->Add(NS_LITERAL_STRING("mixed"));
601 if (state
& states::READONLY
)
602 stringStates
->Add(NS_LITERAL_STRING("readonly"));
603 if (state
& states::HOTTRACKED
)
604 stringStates
->Add(NS_LITERAL_STRING("hottracked"));
605 if (state
& states::DEFAULT
)
606 stringStates
->Add(NS_LITERAL_STRING("default"));
607 if (state
& states::EXPANDED
)
608 stringStates
->Add(NS_LITERAL_STRING("expanded"));
609 if (state
& states::COLLAPSED
)
610 stringStates
->Add(NS_LITERAL_STRING("collapsed"));
611 if (state
& states::BUSY
)
612 stringStates
->Add(NS_LITERAL_STRING("busy"));
613 if (state
& states::FLOATING
)
614 stringStates
->Add(NS_LITERAL_STRING("floating"));
615 if (state
& states::ANIMATED
)
616 stringStates
->Add(NS_LITERAL_STRING("animated"));
617 if (state
& states::INVISIBLE
)
618 stringStates
->Add(NS_LITERAL_STRING("invisible"));
619 if (state
& states::OFFSCREEN
)
620 stringStates
->Add(NS_LITERAL_STRING("offscreen"));
621 if (state
& states::SIZEABLE
)
622 stringStates
->Add(NS_LITERAL_STRING("sizeable"));
623 if (state
& states::MOVEABLE
)
624 stringStates
->Add(NS_LITERAL_STRING("moveable"));
625 if (state
& states::SELFVOICING
)
626 stringStates
->Add(NS_LITERAL_STRING("selfvoicing"));
627 if (state
& states::FOCUSABLE
)
628 stringStates
->Add(NS_LITERAL_STRING("focusable"));
629 if (state
& states::SELECTABLE
)
630 stringStates
->Add(NS_LITERAL_STRING("selectable"));
631 if (state
& states::LINKED
)
632 stringStates
->Add(NS_LITERAL_STRING("linked"));
633 if (state
& states::TRAVERSED
)
634 stringStates
->Add(NS_LITERAL_STRING("traversed"));
635 if (state
& states::MULTISELECTABLE
)
636 stringStates
->Add(NS_LITERAL_STRING("multiselectable"));
637 if (state
& states::EXTSELECTABLE
)
638 stringStates
->Add(NS_LITERAL_STRING("extselectable"));
639 if (state
& states::PROTECTED
)
640 stringStates
->Add(NS_LITERAL_STRING("protected"));
641 if (state
& states::HASPOPUP
)
642 stringStates
->Add(NS_LITERAL_STRING("haspopup"));
643 if (state
& states::REQUIRED
)
644 stringStates
->Add(NS_LITERAL_STRING("required"));
645 if (state
& states::ALERT
)
646 stringStates
->Add(NS_LITERAL_STRING("alert"));
647 if (state
& states::INVALID
)
648 stringStates
->Add(NS_LITERAL_STRING("invalid"));
649 if (state
& states::CHECKABLE
)
650 stringStates
->Add(NS_LITERAL_STRING("checkable"));
653 if (state
& states::SUPPORTS_AUTOCOMPLETION
)
654 stringStates
->Add(NS_LITERAL_STRING("autocompletion"));
655 if (state
& states::DEFUNCT
)
656 stringStates
->Add(NS_LITERAL_STRING("defunct"));
657 if (state
& states::SELECTABLE_TEXT
)
658 stringStates
->Add(NS_LITERAL_STRING("selectable text"));
659 if (state
& states::EDITABLE
)
660 stringStates
->Add(NS_LITERAL_STRING("editable"));
661 if (state
& states::ACTIVE
)
662 stringStates
->Add(NS_LITERAL_STRING("active"));
663 if (state
& states::MODAL
)
664 stringStates
->Add(NS_LITERAL_STRING("modal"));
665 if (state
& states::MULTI_LINE
)
666 stringStates
->Add(NS_LITERAL_STRING("multi line"));
667 if (state
& states::HORIZONTAL
)
668 stringStates
->Add(NS_LITERAL_STRING("horizontal"));
669 if (state
& states::OPAQUE1
)
670 stringStates
->Add(NS_LITERAL_STRING("opaque"));
671 if (state
& states::SINGLE_LINE
)
672 stringStates
->Add(NS_LITERAL_STRING("single line"));
673 if (state
& states::TRANSIENT
)
674 stringStates
->Add(NS_LITERAL_STRING("transient"));
675 if (state
& states::VERTICAL
)
676 stringStates
->Add(NS_LITERAL_STRING("vertical"));
677 if (state
& states::STALE
)
678 stringStates
->Add(NS_LITERAL_STRING("stale"));
679 if (state
& states::ENABLED
)
680 stringStates
->Add(NS_LITERAL_STRING("enabled"));
681 if (state
& states::SENSITIVE
)
682 stringStates
->Add(NS_LITERAL_STRING("sensitive"));
683 if (state
& states::EXPANDABLE
)
684 stringStates
->Add(NS_LITERAL_STRING("expandable"));
687 if (!stringStates
->Length())
688 stringStates
->Add(NS_LITERAL_STRING("unknown"));
690 stringStates
.forget(aStringStates
);
694 // nsIAccessibleRetrieval::getStringEventType()
696 nsAccessibilityService::GetStringEventType(uint32_t aEventType
,
699 NS_ASSERTION(nsIAccessibleEvent::EVENT_LAST_ENTRY
== ArrayLength(kEventTypeNames
),
700 "nsIAccessibleEvent constants are out of sync to kEventTypeNames");
702 if (aEventType
>= ArrayLength(kEventTypeNames
)) {
703 aString
.AssignLiteral("unknown");
707 CopyUTF8toUTF16(kEventTypeNames
[aEventType
], aString
);
711 // nsIAccessibleRetrieval::getStringRelationType()
713 nsAccessibilityService::GetStringRelationType(uint32_t aRelationType
,
716 NS_ENSURE_ARG(aRelationType
<= static_cast<uint32_t>(RelationType::LAST
));
718 #define RELATIONTYPE(geckoType, geckoTypeName, atkType, msaaType, ia2Type) \
719 case RelationType::geckoType: \
720 aString.AssignLiteral(geckoTypeName); \
723 RelationType relationType
= static_cast<RelationType
>(aRelationType
);
724 switch (relationType
) {
725 #include "RelationTypeMap.h"
727 aString
.AssignLiteral("unknown");
735 nsAccessibilityService::GetAccessibleFromCache(nsIDOMNode
* aNode
,
736 nsIAccessible
** aAccessible
)
738 NS_ENSURE_ARG_POINTER(aAccessible
);
739 *aAccessible
= nullptr;
743 nsCOMPtr
<nsINode
> node(do_QueryInterface(aNode
));
745 return NS_ERROR_INVALID_ARG
;
747 // Search for an accessible in each of our per document accessible object
748 // caches. If we don't find it, and the given node is itself a document, check
749 // our cache of document accessibles (document cache). Note usually shutdown
750 // document accessibles are not stored in the document cache, however an
751 // "unofficially" shutdown document (i.e. not from DocManager) can still
752 // exist in the document cache.
753 Accessible
* accessible
= FindAccessibleInCache(node
);
755 nsCOMPtr
<nsIDocument
> document(do_QueryInterface(node
));
757 accessible
= GetExistingDocAccessible(document
);
760 NS_IF_ADDREF(*aAccessible
= accessible
);
765 nsAccessibilityService::CreateAccessiblePivot(nsIAccessible
* aRoot
,
766 nsIAccessiblePivot
** aPivot
)
768 NS_ENSURE_ARG_POINTER(aPivot
);
769 NS_ENSURE_ARG(aRoot
);
772 nsRefPtr
<Accessible
> accessibleRoot(do_QueryObject(aRoot
));
773 NS_ENSURE_TRUE(accessibleRoot
, NS_ERROR_INVALID_ARG
);
775 nsAccessiblePivot
* pivot
= new nsAccessiblePivot(accessibleRoot
);
776 NS_ADDREF(*aPivot
= pivot
);
782 nsAccessibilityService::SetLogging(const nsACString
& aModules
)
785 logging::Enable(PromiseFlatCString(aModules
));
791 nsAccessibilityService::IsLogged(const nsAString
& aModule
, bool* aIsLogged
)
793 NS_ENSURE_ARG_POINTER(aIsLogged
);
797 *aIsLogged
= logging::IsEnabled(aModule
);
803 ////////////////////////////////////////////////////////////////////////////////
804 // nsAccessibilityService public
807 nsAccessibilityService::GetOrCreateAccessible(nsINode
* aNode
,
808 Accessible
* aContext
,
809 bool* aIsSubtreeHidden
)
811 NS_PRECONDITION(aContext
&& aNode
&& !gIsShutdown
,
812 "Maybe let'd do a crash? Oh, yes, baby!");
814 if (aIsSubtreeHidden
)
815 *aIsSubtreeHidden
= false;
817 DocAccessible
* document
= aContext
->Document();
819 // Check to see if we already have an accessible for this node in the cache.
820 // XXX: we don't have context check here. It doesn't really necessary until
821 // we have in-law children adoption.
822 Accessible
* cachedAccessible
= document
->GetAccessible(aNode
);
823 if (cachedAccessible
)
824 return cachedAccessible
;
826 // No cache entry, so we must create the accessible.
828 if (aNode
->IsNodeOfType(nsINode::eDOCUMENT
)) {
829 // If it's document node then ask accessible document loader for
830 // document accessible, otherwise return null.
831 nsCOMPtr
<nsIDocument
> document(do_QueryInterface(aNode
));
832 return GetDocAccessible(document
);
835 // We have a content node.
836 if (!aNode
->GetCrossShadowCurrentDoc()) {
837 NS_WARNING("Creating accessible for node with no document");
841 if (aNode
->OwnerDoc() != document
->DocumentNode()) {
842 NS_ERROR("Creating accessible for wrong document");
846 if (!aNode
->IsContent())
849 nsIContent
* content
= aNode
->AsContent();
850 nsIFrame
* frame
= content
->GetPrimaryFrame();
852 // Check frame and its visibility. Note, hidden frame allows visible
853 // elements in subtree.
854 if (!frame
|| !frame
->StyleVisibility()->IsVisible()) {
855 if (aIsSubtreeHidden
&& !frame
)
856 *aIsSubtreeHidden
= true;
861 if (frame
->GetContent() != content
) {
862 // Not the main content for this frame. This happens because <area>
863 // elements return the image frame as their primary frame. The main content
864 // for the image frame is the image content. If the frame is not an image
865 // frame or the node is not an area element then null is returned.
866 // This setup will change when bug 135040 is fixed. Make sure we don't
867 // create area accessible here. Hopefully assertion below will handle that.
870 nsImageFrame
* imageFrame
= do_QueryFrame(frame
);
871 NS_ASSERTION(imageFrame
&& content
->IsHTML() && content
->Tag() == nsGkAtoms::area
,
872 "Unknown case of not main content for the frame!");
878 nsImageFrame
* imageFrame
= do_QueryFrame(frame
);
879 NS_ASSERTION(!imageFrame
|| !content
->IsHTML() || content
->Tag() != nsGkAtoms::area
,
880 "Image map manages the area accessible creation!");
883 // Attempt to create an accessible based on what we know.
884 nsRefPtr
<Accessible
> newAcc
;
886 // Create accessible for visible text frames.
887 if (content
->IsNodeOfType(nsINode::eTEXT
)) {
889 frame
->GetRenderedText(&text
, nullptr, nullptr, 0, UINT32_MAX
);
890 // Ignore not rendered text nodes and whitespace text nodes between table
892 if (text
.IsEmpty() ||
893 (aContext
->IsTableRow() && nsCoreUtils::IsWhitespaceString(text
))) {
894 if (aIsSubtreeHidden
)
895 *aIsSubtreeHidden
= true;
900 newAcc
= CreateAccessibleByFrameType(frame
, content
, aContext
);
901 if (!aContext
->IsAcceptableChild(newAcc
))
904 document
->BindToDocument(newAcc
, nullptr);
905 newAcc
->AsTextLeaf()->SetText(text
);
909 bool isHTML
= content
->IsHTML();
910 if (isHTML
&& content
->Tag() == nsGkAtoms::map
) {
911 // Create hyper text accessible for HTML map if it is used to group links
912 // (see http://www.w3.org/TR/WCAG10-HTML-TECHS/#group-bypass). If the HTML
913 // map rect is empty then it is used for links grouping. Otherwise it should
914 // be used in conjunction with HTML image element and in this case we don't
915 // create any accessible for it and don't walk into it. The accessibles for
916 // HTML area (HTMLAreaAccessible) the map contains are attached as
917 // children of the appropriate accessible for HTML image
918 // (ImageAccessible).
919 if (nsLayoutUtils::GetAllInFlowRectsUnion(frame
,
920 frame
->GetParent()).IsEmpty()) {
921 if (aIsSubtreeHidden
)
922 *aIsSubtreeHidden
= true;
927 newAcc
= new HyperTextAccessibleWrap(content
, document
);
928 if (!aContext
->IsAcceptableChild(newAcc
))
931 document
->BindToDocument(newAcc
, aria::GetRoleMap(aNode
));
935 nsRoleMapEntry
* roleMapEntry
= aria::GetRoleMap(aNode
);
937 // If the element is focusable or global ARIA attribute is applied to it or
938 // it is referenced by ARIA relationship then treat role="presentation" on
939 // the element as the role is not there.
940 if (roleMapEntry
&& roleMapEntry
->Is(nsGkAtoms::presentation
)) {
941 if (!MustBeAccessible(content
, document
))
944 roleMapEntry
= nullptr;
947 if (!newAcc
&& isHTML
) { // HTML accessibles
949 // Create pure ARIA grid/treegrid related accessibles if they weren't used
950 // on accessible HTML table elements.
951 if ((roleMapEntry
->accTypes
& eTableCell
)) {
952 if (aContext
->IsTableRow() &&
953 (frame
->AccessibleType() != eHTMLTableCellType
||
954 aContext
->GetContent() != content
->GetParent())) {
955 newAcc
= new ARIAGridCellAccessibleWrap(content
, document
);
958 } else if ((roleMapEntry
->IsOfType(eTable
)) &&
959 frame
->AccessibleType() != eHTMLTableType
) {
960 newAcc
= new ARIAGridAccessibleWrap(content
, document
);
965 // Prefer to use markup (mostly tag name, perhaps attributes) to decide if
966 // and what kind of accessible to create.
967 newAcc
= CreateHTMLAccessibleByMarkup(frame
, content
, aContext
);
969 // Try using frame to do it.
971 newAcc
= CreateAccessibleByFrameType(frame
, content
, aContext
);
973 // If table has strong ARIA role then all table descendants shouldn't
974 // expose their native roles.
975 if (!roleMapEntry
&& newAcc
&& aContext
->HasStrongARIARole()) {
976 if (frame
->AccessibleType() == eHTMLTableRowType
) {
977 nsRoleMapEntry
* contextRoleMap
= aContext
->ARIARoleMap();
978 if (!contextRoleMap
->IsOfType(eTable
))
979 roleMapEntry
= &aria::gEmptyRoleMap
;
981 } else if (frame
->AccessibleType() == eHTMLTableCellType
&&
982 aContext
->ARIARoleMap() == &aria::gEmptyRoleMap
) {
983 roleMapEntry
= &aria::gEmptyRoleMap
;
985 } else if (content
->Tag() == nsGkAtoms::dt
||
986 content
->Tag() == nsGkAtoms::li
||
987 content
->Tag() == nsGkAtoms::dd
||
988 frame
->AccessibleType() == eHTMLLiType
) {
989 nsRoleMapEntry
* contextRoleMap
= aContext
->ARIARoleMap();
990 if (!contextRoleMap
->IsOfType(eList
))
991 roleMapEntry
= &aria::gEmptyRoleMap
;
997 // Accessible XBL types and deck stuff are used in XUL only currently.
998 if (!newAcc
&& content
->IsXUL()) {
999 // No accessible for not selected deck panel and its children.
1000 if (!aContext
->IsXULTabpanels()) {
1001 nsDeckFrame
* deckFrame
= do_QueryFrame(frame
->GetParent());
1002 if (deckFrame
&& deckFrame
->GetSelectedBox() != frame
) {
1003 if (aIsSubtreeHidden
)
1004 *aIsSubtreeHidden
= true;
1010 // XBL bindings may use @role attribute to point the accessible type
1012 newAcc
= CreateAccessibleByType(content
, document
);
1014 // Any XUL box can be used as tabpanel, make sure we create a proper
1015 // accessible for it.
1016 if (!newAcc
&& aContext
->IsXULTabpanels() &&
1017 content
->GetParent() == aContext
->GetContent()) {
1018 nsIAtom
* frameType
= frame
->GetType();
1019 if (frameType
== nsGkAtoms::boxFrame
||
1020 frameType
== nsGkAtoms::scrollFrame
) {
1021 newAcc
= new XULTabpanelAccessible(content
, document
);
1027 if (content
->IsSVG()) {
1028 nsSVGPathGeometryFrame
* pathGeometryFrame
= do_QueryFrame(frame
);
1029 if (pathGeometryFrame
) {
1030 // A graphic elements: rect, circle, ellipse, line, path, polygon,
1031 // polyline and image. A 'use' and 'text' graphic elements require
1033 newAcc
= new EnumRoleAccessible(content
, document
, roles::GRAPHIC
);
1034 } else if (content
->Tag() == nsGkAtoms::svg
) {
1035 newAcc
= new EnumRoleAccessible(content
, document
, roles::DIAGRAM
);
1037 } else if (content
->IsMathML()){
1038 if (content
->Tag() == nsGkAtoms::math
)
1039 newAcc
= new EnumRoleAccessible(content
, document
, roles::EQUATION
);
1041 newAcc
= new HyperTextAccessible(content
, document
);
1045 // If no accessible, see if we need to create a generic accessible because
1046 // of some property that makes this object interesting
1047 // We don't do this for <body>, <html>, <window>, <dialog> etc. which
1048 // correspond to the doc accessible and will be created in any case
1049 if (!newAcc
&& content
->Tag() != nsGkAtoms::body
&& content
->GetParent() &&
1050 (roleMapEntry
|| MustBeAccessible(content
, document
) ||
1051 (isHTML
&& nsCoreUtils::HasClickListener(content
)))) {
1052 // This content is focusable or has an interesting dynamic content accessibility property.
1053 // If it's interesting we need it in the accessibility hierarchy so that events or
1054 // other accessibles can point to it, or so that it can hold a state, etc.
1056 // Interesting HTML container which may have selectable text and/or embedded objects
1057 newAcc
= new HyperTextAccessibleWrap(content
, document
);
1058 } else { // XUL, SVG, MathML etc.
1059 // Interesting generic non-HTML container
1060 newAcc
= new AccessibleWrap(content
, document
);
1064 if (!newAcc
|| !aContext
->IsAcceptableChild(newAcc
))
1067 document
->BindToDocument(newAcc
, roleMapEntry
);
1071 ////////////////////////////////////////////////////////////////////////////////
1072 // nsAccessibilityService private
1075 nsAccessibilityService::Init()
1077 // Initialize accessible document manager.
1078 if (!DocManager::Init())
1082 nsCOMPtr
<nsIObserverService
> observerService
=
1083 mozilla::services::GetObserverService();
1084 if (!observerService
)
1087 observerService
->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID
, false);
1089 static const char16_t kInitIndicator
[] = { '1', 0 };
1090 observerService
->NotifyObservers(nullptr, "a11y-init-or-shutdown", kInitIndicator
);
1093 logging::CheckEnv();
1096 gApplicationAccessible
= new ApplicationAccessibleWrap();
1097 NS_ADDREF(gApplicationAccessible
); // will release in Shutdown()
1099 #ifdef MOZ_CRASHREPORTER
1101 AnnotateCrashReport(NS_LITERAL_CSTRING("Accessibility"),
1102 NS_LITERAL_CSTRING("Active"));
1106 sPendingPlugins
= new nsTArray
<nsCOMPtr
<nsIContent
> >;
1107 sPluginTimers
= new nsTArray
<nsCOMPtr
<nsITimer
> >;
1110 gIsShutdown
= false;
1112 // Now its safe to start platform accessibility.
1119 nsAccessibilityService::Shutdown()
1121 // Remove observers.
1122 nsCOMPtr
<nsIObserverService
> observerService
=
1123 mozilla::services::GetObserverService();
1124 if (observerService
) {
1125 observerService
->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID
);
1127 static const char16_t kShutdownIndicator
[] = { '0', 0 };
1128 observerService
->NotifyObservers(nullptr, "a11y-init-or-shutdown", kShutdownIndicator
);
1131 // Stop accessible document loader.
1132 DocManager::Shutdown();
1134 SelectionManager::Shutdown();
1137 sPendingPlugins
= nullptr;
1139 uint32_t timerCount
= sPluginTimers
->Length();
1140 for (uint32_t i
= 0; i
< timerCount
; i
++)
1141 sPluginTimers
->ElementAt(i
)->Cancel();
1143 sPluginTimers
= nullptr;
1146 // Application is going to be closed, shutdown accessibility and mark
1147 // accessibility service as shutdown to prevent calls of its methods.
1148 // Don't null accessibility service static member at this point to be safe
1149 // if someone will try to operate with it.
1151 NS_ASSERTION(!gIsShutdown
, "Accessibility was shutdown already");
1156 gApplicationAccessible
->Shutdown();
1157 NS_RELEASE(gApplicationAccessible
);
1158 gApplicationAccessible
= nullptr;
1161 already_AddRefed
<Accessible
>
1162 nsAccessibilityService::CreateAccessibleByType(nsIContent
* aContent
,
1163 DocAccessible
* aDoc
)
1166 for (const nsXBLBinding
* binding
= aContent
->GetXBLBinding(); binding
; binding
= binding
->GetBaseBinding()) {
1167 nsIContent
* bindingElm
= binding
->PrototypeBinding()->GetBindingElement();
1168 bindingElm
->GetAttr(kNameSpaceID_None
, nsGkAtoms::role
, role
);
1169 if (!role
.IsEmpty())
1173 if (role
.IsEmpty() || role
.EqualsLiteral("none"))
1176 if (role
.EqualsLiteral("outerdoc")) {
1177 nsRefPtr
<Accessible
> accessible
= new OuterDocAccessible(aContent
, aDoc
);
1178 return accessible
.forget();
1181 nsRefPtr
<Accessible
> accessible
;
1184 if (role
.EqualsLiteral("xul:alert")) {
1185 accessible
= new XULAlertAccessible(aContent
, aDoc
);
1187 } else if (role
.EqualsLiteral("xul:button")) {
1188 accessible
= new XULButtonAccessible(aContent
, aDoc
);
1190 } else if (role
.EqualsLiteral("xul:checkbox")) {
1191 accessible
= new XULCheckboxAccessible(aContent
, aDoc
);
1193 } else if (role
.EqualsLiteral("xul:colorpicker")) {
1194 accessible
= new XULColorPickerAccessible(aContent
, aDoc
);
1196 } else if (role
.EqualsLiteral("xul:colorpickertile")) {
1197 accessible
= new XULColorPickerTileAccessible(aContent
, aDoc
);
1199 } else if (role
.EqualsLiteral("xul:combobox")) {
1200 accessible
= new XULComboboxAccessible(aContent
, aDoc
);
1202 } else if (role
.EqualsLiteral("xul:tabpanels")) {
1203 accessible
= new XULTabpanelsAccessible(aContent
, aDoc
);
1205 } else if (role
.EqualsLiteral("xul:dropmarker")) {
1206 accessible
= new XULDropmarkerAccessible(aContent
, aDoc
);
1208 } else if (role
.EqualsLiteral("xul:groupbox")) {
1209 accessible
= new XULGroupboxAccessible(aContent
, aDoc
);
1211 } else if (role
.EqualsLiteral("xul:image")) {
1212 if (aContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::onclick
)) {
1213 accessible
= new XULToolbarButtonAccessible(aContent
, aDoc
);
1216 // Don't include nameless images in accessible tree.
1217 if (!aContent
->HasAttr(kNameSpaceID_None
,
1218 nsGkAtoms::tooltiptext
))
1221 accessible
= new ImageAccessibleWrap(aContent
, aDoc
);
1224 } else if (role
.EqualsLiteral("xul:link")) {
1225 accessible
= new XULLinkAccessible(aContent
, aDoc
);
1227 } else if (role
.EqualsLiteral("xul:listbox")) {
1228 accessible
= new XULListboxAccessibleWrap(aContent
, aDoc
);
1230 } else if (role
.EqualsLiteral("xul:listcell")) {
1231 // Only create cells if there's more than one per row.
1232 nsIContent
* listItem
= aContent
->GetParent();
1236 for (nsIContent
* child
= listItem
->GetFirstChild(); child
;
1237 child
= child
->GetNextSibling()) {
1238 if (child
->IsXUL(nsGkAtoms::listcell
) && child
!= aContent
) {
1239 accessible
= new XULListCellAccessibleWrap(aContent
, aDoc
);
1244 } else if (role
.EqualsLiteral("xul:listhead")) {
1245 accessible
= new XULColumAccessible(aContent
, aDoc
);
1247 } else if (role
.EqualsLiteral("xul:listheader")) {
1248 accessible
= new XULColumnItemAccessible(aContent
, aDoc
);
1250 } else if (role
.EqualsLiteral("xul:listitem")) {
1251 accessible
= new XULListitemAccessible(aContent
, aDoc
);
1253 } else if (role
.EqualsLiteral("xul:menubar")) {
1254 accessible
= new XULMenubarAccessible(aContent
, aDoc
);
1256 } else if (role
.EqualsLiteral("xul:menulist")) {
1257 accessible
= new XULComboboxAccessible(aContent
, aDoc
);
1259 } else if (role
.EqualsLiteral("xul:menuitem")) {
1260 accessible
= new XULMenuitemAccessibleWrap(aContent
, aDoc
);
1262 } else if (role
.EqualsLiteral("xul:menupopup")) {
1263 #ifdef MOZ_ACCESSIBILITY_ATK
1264 // ATK considers this node to be redundant when within menubars, and it makes menu
1265 // navigation with assistive technologies more difficult
1266 // XXX In the future we will should this for consistency across the nsIAccessible
1267 // implementations on each platform for a consistent scripting environment, but
1268 // then strip out redundant accessibles in the AccessibleWrap class for each platform.
1269 nsIContent
*parent
= aContent
->GetParent();
1270 if (parent
&& parent
->IsXUL() && parent
->Tag() == nsGkAtoms::menu
)
1274 accessible
= new XULMenupopupAccessible(aContent
, aDoc
);
1276 } else if(role
.EqualsLiteral("xul:menuseparator")) {
1277 accessible
= new XULMenuSeparatorAccessible(aContent
, aDoc
);
1279 } else if(role
.EqualsLiteral("xul:pane")) {
1280 accessible
= new EnumRoleAccessible(aContent
, aDoc
, roles::PANE
);
1282 } else if (role
.EqualsLiteral("xul:panel")) {
1283 if (aContent
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::noautofocus
,
1284 nsGkAtoms::_true
, eCaseMatters
))
1285 accessible
= new XULAlertAccessible(aContent
, aDoc
);
1287 accessible
= new EnumRoleAccessible(aContent
, aDoc
, roles::PANE
);
1289 } else if (role
.EqualsLiteral("xul:progressmeter")) {
1290 accessible
= new XULProgressMeterAccessible(aContent
, aDoc
);
1292 } else if (role
.EqualsLiteral("xul:statusbar")) {
1293 accessible
= new XULStatusBarAccessible(aContent
, aDoc
);
1295 } else if (role
.EqualsLiteral("xul:scale")) {
1296 accessible
= new XULSliderAccessible(aContent
, aDoc
);
1298 } else if (role
.EqualsLiteral("xul:radiobutton")) {
1299 accessible
= new XULRadioButtonAccessible(aContent
, aDoc
);
1301 } else if (role
.EqualsLiteral("xul:radiogroup")) {
1302 accessible
= new XULRadioGroupAccessible(aContent
, aDoc
);
1304 } else if (role
.EqualsLiteral("xul:tab")) {
1305 accessible
= new XULTabAccessible(aContent
, aDoc
);
1307 } else if (role
.EqualsLiteral("xul:tabs")) {
1308 accessible
= new XULTabsAccessible(aContent
, aDoc
);
1310 } else if (role
.EqualsLiteral("xul:text")) {
1311 accessible
= new XULLabelAccessible(aContent
, aDoc
);
1313 } else if (role
.EqualsLiteral("xul:textbox")) {
1314 accessible
= new EnumRoleAccessible(aContent
, aDoc
, roles::SECTION
);
1316 } else if (role
.EqualsLiteral("xul:thumb")) {
1317 accessible
= new XULThumbAccessible(aContent
, aDoc
);
1319 } else if (role
.EqualsLiteral("xul:tree")) {
1320 accessible
= CreateAccessibleForXULTree(aContent
, aDoc
);
1322 } else if (role
.EqualsLiteral("xul:treecolumns")) {
1323 accessible
= new XULTreeColumAccessible(aContent
, aDoc
);
1325 } else if (role
.EqualsLiteral("xul:treecolumnitem")) {
1326 accessible
= new XULColumnItemAccessible(aContent
, aDoc
);
1328 } else if (role
.EqualsLiteral("xul:toolbar")) {
1329 accessible
= new XULToolbarAccessible(aContent
, aDoc
);
1331 } else if (role
.EqualsLiteral("xul:toolbarseparator")) {
1332 accessible
= new XULToolbarSeparatorAccessible(aContent
, aDoc
);
1334 } else if (role
.EqualsLiteral("xul:tooltip")) {
1335 accessible
= new XULTooltipAccessible(aContent
, aDoc
);
1337 } else if (role
.EqualsLiteral("xul:toolbarbutton")) {
1338 accessible
= new XULToolbarButtonAccessible(aContent
, aDoc
);
1343 return accessible
.forget();
1346 already_AddRefed
<Accessible
>
1347 nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame
* aFrame
,
1348 nsIContent
* aContent
,
1349 Accessible
* aContext
)
1351 DocAccessible
* document
= aContext
->Document();
1352 if (aContext
->IsTableRow()) {
1353 if (nsCoreUtils::IsHTMLTableHeader(aContent
) &&
1354 aContext
->GetContent() == aContent
->GetParent()) {
1355 nsRefPtr
<Accessible
> accessible
=
1356 new HTMLTableHeaderCellAccessibleWrap(aContent
, document
);
1357 return accessible
.forget();
1363 // This method assumes we're in an HTML namespace.
1364 nsIAtom
* tag
= aContent
->Tag();
1365 if (tag
== nsGkAtoms::figcaption
) {
1366 nsRefPtr
<Accessible
> accessible
=
1367 new HTMLFigcaptionAccessible(aContent
, document
);
1368 return accessible
.forget();
1371 if (tag
== nsGkAtoms::figure
) {
1372 nsRefPtr
<Accessible
> accessible
=
1373 new HTMLFigureAccessible(aContent
, document
);
1374 return accessible
.forget();
1377 if (tag
== nsGkAtoms::legend
) {
1378 nsRefPtr
<Accessible
> accessible
=
1379 new HTMLLegendAccessible(aContent
, document
);
1380 return accessible
.forget();
1383 if (tag
== nsGkAtoms::option
) {
1384 nsRefPtr
<Accessible
> accessible
=
1385 new HTMLSelectOptionAccessible(aContent
, document
);
1386 return accessible
.forget();
1389 if (tag
== nsGkAtoms::optgroup
) {
1390 nsRefPtr
<Accessible
> accessible
=
1391 new HTMLSelectOptGroupAccessible(aContent
, document
);
1392 return accessible
.forget();
1395 if (tag
== nsGkAtoms::ul
|| tag
== nsGkAtoms::ol
||
1396 tag
== nsGkAtoms::dl
) {
1397 nsRefPtr
<Accessible
> accessible
=
1398 new HTMLListAccessible(aContent
, document
);
1399 return accessible
.forget();
1402 if (tag
== nsGkAtoms::a
) {
1403 // Only some roles truly enjoy life as HTMLLinkAccessibles, for details
1404 // see closed bug 494807.
1405 nsRoleMapEntry
* roleMapEntry
= aria::GetRoleMap(aContent
);
1406 if (roleMapEntry
&& roleMapEntry
->role
!= roles::NOTHING
&&
1407 roleMapEntry
->role
!= roles::LINK
) {
1408 nsRefPtr
<Accessible
> accessible
=
1409 new HyperTextAccessibleWrap(aContent
, document
);
1410 return accessible
.forget();
1413 nsRefPtr
<Accessible
> accessible
=
1414 new HTMLLinkAccessible(aContent
, document
);
1415 return accessible
.forget();
1418 if (aContext
->IsList()) {
1419 // If list item is a child of accessible list then create an accessible for
1420 // it unconditionally by tag name. nsBlockFrame creates the list item
1421 // accessible for other elements styled as list items.
1422 if (aContext
->GetContent() == aContent
->GetParent()) {
1423 if (tag
== nsGkAtoms::dt
|| tag
== nsGkAtoms::li
) {
1424 nsRefPtr
<Accessible
> accessible
=
1425 new HTMLLIAccessible(aContent
, document
);
1426 return accessible
.forget();
1429 if (tag
== nsGkAtoms::dd
) {
1430 nsRefPtr
<Accessible
> accessible
=
1431 new HyperTextAccessibleWrap(aContent
, document
);
1432 return accessible
.forget();
1439 if (tag
== nsGkAtoms::abbr
||
1440 tag
== nsGkAtoms::acronym
||
1441 tag
== nsGkAtoms::article
||
1442 tag
== nsGkAtoms::aside
||
1443 tag
== nsGkAtoms::blockquote
||
1444 tag
== nsGkAtoms::form
||
1445 tag
== nsGkAtoms::footer
||
1446 tag
== nsGkAtoms::header
||
1447 tag
== nsGkAtoms::h1
||
1448 tag
== nsGkAtoms::h2
||
1449 tag
== nsGkAtoms::h3
||
1450 tag
== nsGkAtoms::h4
||
1451 tag
== nsGkAtoms::h5
||
1452 tag
== nsGkAtoms::h6
||
1453 tag
== nsGkAtoms::nav
||
1454 tag
== nsGkAtoms::q
||
1455 tag
== nsGkAtoms::section
) {
1456 nsRefPtr
<Accessible
> accessible
=
1457 new HyperTextAccessibleWrap(aContent
, document
);
1458 return accessible
.forget();
1461 if (tag
== nsGkAtoms::label
) {
1462 nsRefPtr
<Accessible
> accessible
=
1463 new HTMLLabelAccessible(aContent
, document
);
1464 return accessible
.forget();
1467 if (tag
== nsGkAtoms::output
) {
1468 nsRefPtr
<Accessible
> accessible
=
1469 new HTMLOutputAccessible(aContent
, document
);
1470 return accessible
.forget();
1473 if (tag
== nsGkAtoms::progress
) {
1474 nsRefPtr
<Accessible
> accessible
=
1475 new HTMLProgressMeterAccessible(aContent
, document
);
1476 return accessible
.forget();
1482 already_AddRefed
<Accessible
>
1483 nsAccessibilityService::CreateAccessibleByFrameType(nsIFrame
* aFrame
,
1484 nsIContent
* aContent
,
1485 Accessible
* aContext
)
1487 DocAccessible
* document
= aContext
->Document();
1489 nsRefPtr
<Accessible
> newAcc
;
1490 switch (aFrame
->AccessibleType()) {
1494 newAcc
= new HTMLBRAccessible(aContent
, document
);
1496 case eHTMLButtonType
:
1497 newAcc
= new HTMLButtonAccessible(aContent
, document
);
1499 case eHTMLCanvasType
:
1500 newAcc
= new HTMLCanvasAccessible(aContent
, document
);
1502 case eHTMLCaptionType
:
1503 if (aContext
->IsTable() &&
1504 aContext
->GetContent() == aContent
->GetParent()) {
1505 newAcc
= new HTMLCaptionAccessible(aContent
, document
);
1508 case eHTMLCheckboxType
:
1509 newAcc
= new HTMLCheckboxAccessible(aContent
, document
);
1511 case eHTMLComboboxType
:
1512 newAcc
= new HTMLComboboxAccessible(aContent
, document
);
1514 case eHTMLFileInputType
:
1515 newAcc
= new HTMLFileInputAccessible(aContent
, document
);
1517 case eHTMLGroupboxType
:
1518 newAcc
= new HTMLGroupboxAccessible(aContent
, document
);
1521 newAcc
= new HTMLHRAccessible(aContent
, document
);
1523 case eHTMLImageMapType
:
1524 newAcc
= new HTMLImageMapAccessible(aContent
, document
);
1527 if (aContext
->IsList() &&
1528 aContext
->GetContent() == aContent
->GetParent()) {
1529 newAcc
= new HTMLLIAccessible(aContent
, document
);
1532 case eHTMLSelectListType
:
1533 newAcc
= new HTMLSelectListAccessible(aContent
, document
);
1535 case eHTMLMediaType
:
1536 newAcc
= new EnumRoleAccessible(aContent
, document
, roles::GROUPING
);
1538 case eHTMLRadioButtonType
:
1539 newAcc
= new HTMLRadioButtonAccessible(aContent
, document
);
1541 case eHTMLRangeType
:
1542 newAcc
= new HTMLRangeAccessible(aContent
, document
);
1544 case eHTMLSpinnerType
:
1545 newAcc
= new HTMLSpinnerAccessible(aContent
, document
);
1547 case eHTMLTableType
:
1548 newAcc
= new HTMLTableAccessibleWrap(aContent
, document
);
1550 case eHTMLTableCellType
:
1551 // Accessible HTML table cell should be a child of accessible HTML table
1552 // or its row (CSS HTML tables are polite to the used markup at
1554 // Otherwise create a generic text accessible to avoid text jamming
1555 // when reading by AT.
1556 if (aContext
->IsHTMLTableRow() || aContext
->IsHTMLTable())
1557 newAcc
= new HTMLTableCellAccessibleWrap(aContent
, document
);
1559 newAcc
= new HyperTextAccessibleWrap(aContent
, document
);
1562 case eHTMLTableRowType
: {
1563 // Accessible HTML table row may be a child of tbody/tfoot/thead of
1564 // accessible HTML table or a direct child of accessible of HTML table.
1565 Accessible
* table
= aContext
->IsTable() ? aContext
: nullptr;
1566 if (!table
&& aContext
->Parent() && aContext
->Parent()->IsTable())
1567 table
= aContext
->Parent();
1570 nsIContent
* parentContent
= aContent
->GetParent();
1571 nsIFrame
* parentFrame
= parentContent
->GetPrimaryFrame();
1572 if (parentFrame
->GetType() != nsGkAtoms::tableOuterFrame
) {
1573 parentContent
= parentContent
->GetParent();
1574 parentFrame
= parentContent
->GetPrimaryFrame();
1577 if (parentFrame
->GetType() == nsGkAtoms::tableOuterFrame
&&
1578 table
->GetContent() == parentContent
) {
1579 newAcc
= new HTMLTableRowAccessible(aContent
, document
);
1584 case eHTMLTextFieldType
:
1585 newAcc
= new HTMLTextFieldAccessible(aContent
, document
);
1587 case eHyperTextType
:
1588 if (aContent
->Tag() != nsGkAtoms::dt
&& aContent
->Tag() != nsGkAtoms::dd
)
1589 newAcc
= new HyperTextAccessibleWrap(aContent
, document
);
1593 newAcc
= new ImageAccessibleWrap(aContent
, document
);
1596 newAcc
= new OuterDocAccessible(aContent
, document
);
1599 nsObjectFrame
* objectFrame
= do_QueryFrame(aFrame
);
1600 newAcc
= CreatePluginAccessible(objectFrame
, aContent
, aContext
);
1604 newAcc
= new TextLeafAccessibleWrap(aContent
, document
);
1611 return newAcc
.forget();
1614 ////////////////////////////////////////////////////////////////////////////////
1615 // nsIAccessibilityService (DON'T put methods here)
1618 nsAccessibilityService::AddNativeRootAccessible(void* aAtkAccessible
)
1620 #ifdef MOZ_ACCESSIBILITY_ATK
1621 ApplicationAccessible
* applicationAcc
= ApplicationAcc();
1622 if (!applicationAcc
)
1625 GtkWindowAccessible
* nativeWnd
=
1626 new GtkWindowAccessible(static_cast<AtkObject
*>(aAtkAccessible
));
1628 if (applicationAcc
->AppendChild(nativeWnd
))
1636 nsAccessibilityService::RemoveNativeRootAccessible(Accessible
* aAccessible
)
1638 #ifdef MOZ_ACCESSIBILITY_ATK
1639 ApplicationAccessible
* applicationAcc
= ApplicationAcc();
1642 applicationAcc
->RemoveChild(aAccessible
);
1646 ////////////////////////////////////////////////////////////////////////////////
1647 // NS_GetAccessibilityService
1648 ////////////////////////////////////////////////////////////////////////////////
1651 * Return accessibility service; creating one if necessary.
1654 NS_GetAccessibilityService(nsIAccessibilityService
** aResult
)
1656 NS_ENSURE_TRUE(aResult
, NS_ERROR_NULL_POINTER
);
1659 if (nsAccessibilityService::gAccessibilityService
) {
1660 NS_ADDREF(*aResult
= nsAccessibilityService::gAccessibilityService
);
1664 nsRefPtr
<nsAccessibilityService
> service
= new nsAccessibilityService();
1665 NS_ENSURE_TRUE(service
, NS_ERROR_OUT_OF_MEMORY
);
1667 if (!service
->Init()) {
1668 service
->Shutdown();
1669 return NS_ERROR_FAILURE
;
1672 statistics::A11yInitialized();
1674 nsAccessibilityService::gAccessibilityService
= service
;
1675 NS_ADDREF(*aResult
= service
);
1680 ////////////////////////////////////////////////////////////////////////////////
1681 // nsAccessibilityService private (DON'T put methods here)
1684 already_AddRefed
<Accessible
>
1685 nsAccessibilityService::CreateAccessibleForXULTree(nsIContent
* aContent
,
1686 DocAccessible
* aDoc
)
1688 nsIContent
* child
= nsTreeUtils::GetDescendantChild(aContent
,
1689 nsGkAtoms::treechildren
);
1693 nsTreeBodyFrame
* treeFrame
= do_QueryFrame(child
->GetPrimaryFrame());
1697 nsRefPtr
<nsTreeColumns
> treeCols
= treeFrame
->Columns();
1699 treeCols
->GetCount(&count
);
1701 // Outline of list accessible.
1703 nsRefPtr
<Accessible
> accessible
=
1704 new XULTreeAccessible(aContent
, aDoc
, treeFrame
);
1705 return accessible
.forget();
1708 // Table or tree table accessible.
1709 nsRefPtr
<Accessible
> accessible
=
1710 new XULTreeGridAccessibleWrap(aContent
, aDoc
, treeFrame
);
1711 return accessible
.forget();
1715 ////////////////////////////////////////////////////////////////////////////////
1717 ////////////////////////////////////////////////////////////////////////////////
1725 return nsAccessibilityService::gAccessibilityService
;
1731 return nsAccessibilityService::gAccessibilityService
;
1734 ApplicationAccessible
*
1737 return nsAccessibilityService::gApplicationAccessible
;
1740 EPlatformDisabledState
1741 PlatformDisabledState()
1743 static int disabledState
= 0xff;
1745 if (disabledState
== 0xff) {
1746 disabledState
= Preferences::GetInt("accessibility.force_disabled", 0);
1747 if (disabledState
< ePlatformIsForceEnabled
)
1748 disabledState
= ePlatformIsForceEnabled
;
1749 else if (disabledState
> ePlatformIsDisabled
)
1750 disabledState
= ePlatformIsDisabled
;
1753 return (EPlatformDisabledState
)disabledState
;