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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_a11y_DocAccessible_inl_h_
8 #define mozilla_a11y_DocAccessible_inl_h_
10 #include "DocAccessible.h"
11 #include "LocalAccessible-inl.h"
12 #include "nsAccessibilityService.h"
13 #include "NotificationController.h"
15 #include "nsIScrollableFrame.h"
16 #include "mozilla/dom/DocumentInlines.h"
25 inline LocalAccessible
* DocAccessible::AccessibleOrTrueContainer(
26 nsINode
* aNode
, bool aNoContainerIfPruned
) const {
27 // HTML comboboxes have no-content list accessible as an intermediate
28 // containing all options.
29 LocalAccessible
* container
=
30 GetAccessibleOrContainer(aNode
, aNoContainerIfPruned
);
31 if (container
&& container
->IsHTMLCombobox()) {
32 return container
->LocalFirstChild();
37 inline bool DocAccessible::IsContentLoaded() const {
38 // eDOMLoaded flag check is used for error pages as workaround to make this
39 // method return correct result since error pages do not receive 'pageshow'
40 // event and as consequence Document::IsShowing() returns false.
41 return mDocumentNode
&& mDocumentNode
->IsVisible() &&
42 (mDocumentNode
->IsShowing() || HasLoadState(eDOMLoaded
));
45 inline bool DocAccessible::IsHidden() const { return mDocumentNode
->Hidden(); }
47 inline void DocAccessible::FireDelayedEvent(AccEvent
* aEvent
) {
49 if (logging::IsEnabled(logging::eDocLoad
)) logging::DocLoadEventFired(aEvent
);
52 mNotificationController
->QueueEvent(aEvent
);
55 inline void DocAccessible::FireDelayedEvent(uint32_t aEventType
,
56 LocalAccessible
* aTarget
) {
57 RefPtr
<AccEvent
> event
= new AccEvent(aEventType
, aTarget
);
58 FireDelayedEvent(event
);
61 inline void DocAccessible::BindChildDocument(DocAccessible
* aDocument
) {
62 mNotificationController
->ScheduleChildDocBinding(aDocument
);
65 template <class Class
, class... Args
>
66 inline void DocAccessible::HandleNotification(
67 Class
* aInstance
, typename TNotification
<Class
, Args
...>::Callback aMethod
,
69 if (mNotificationController
) {
70 mNotificationController
->HandleNotification
<Class
, Args
...>(
71 aInstance
, aMethod
, aArgs
...);
75 inline void DocAccessible::UpdateText(nsIContent
* aTextNode
) {
76 NS_ASSERTION(mNotificationController
, "The document was shut down!");
78 // Ignore the notification if initial tree construction hasn't been done yet.
79 if (mNotificationController
&& HasLoadState(eTreeConstructed
)) {
80 mNotificationController
->ScheduleTextUpdate(aTextNode
);
84 inline void DocAccessible::NotifyOfLoad(uint32_t aLoadEventType
) {
85 mLoadState
|= eDOMLoaded
;
86 mLoadEventType
= aLoadEventType
;
88 // If the document is loaded completely then network activity was presumingly
89 // caused by file loading. Fire busy state change event.
90 if (HasLoadState(eCompletelyLoaded
) && IsLoadEventTarget()) {
91 RefPtr
<AccEvent
> stateEvent
=
92 new AccStateChangeEvent(this, states::BUSY
, false);
93 FireDelayedEvent(stateEvent
);
97 inline void DocAccessible::MaybeNotifyOfValueChange(
98 LocalAccessible
* aAccessible
) {
99 if (aAccessible
->IsCombobox() || aAccessible
->Role() == roles::ENTRY
||
100 aAccessible
->Role() == roles::SPINBUTTON
) {
101 FireDelayedEvent(nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE
, aAccessible
);
105 inline LocalAccessible
* DocAccessible::GetAccessibleEvenIfNotInMapOrContainer(
106 nsINode
* aNode
) const {
107 LocalAccessible
* acc
= GetAccessibleEvenIfNotInMap(aNode
);
108 return acc
? acc
: GetContainerAccessible(aNode
);
111 inline void DocAccessible::CreateSubtree(LocalAccessible
* aChild
) {
112 // If a focused node has been shown then it could mean its frame was recreated
113 // while the node stays focused and we need to fire focus event on
114 // the accessible we just created. If the queue contains a focus event for
115 // this node already then it will be suppressed by this one.
116 LocalAccessible
* focusedAcc
= nullptr;
117 CacheChildrenInSubtree(aChild
, &focusedAcc
);
120 if (logging::IsEnabled(logging::eVerbose
)) {
121 logging::Tree("TREE", "Created subtree", aChild
);
125 // Fire events for ARIA elements.
126 if (aChild
->HasARIARole()) {
127 roles::Role role
= aChild
->ARIARole();
128 if (role
== roles::MENUPOPUP
) {
129 FireDelayedEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START
, aChild
);
130 } else if (role
== roles::ALERT
) {
131 FireDelayedEvent(nsIAccessibleEvent::EVENT_ALERT
, aChild
);
135 // XXX: do we really want to send focus to focused DOM node not taking into
136 // account active item?
138 FocusMgr()->DispatchFocusEvent(this, focusedAcc
);
139 SelectionMgr()->SetControlSelectionListener(
140 focusedAcc
->GetNode()->AsElement());
144 inline DocAccessible::AttrRelProviders
* DocAccessible::GetRelProviders(
145 dom::Element
* aElement
, const nsAString
& aID
) const {
146 DependentIDsHashtable
* hash
= mDependentIDsHashes
.Get(
147 aElement
->GetUncomposedDocOrConnectedShadowRoot());
149 return hash
->Get(aID
);
154 inline DocAccessible::AttrRelProviders
* DocAccessible::GetOrCreateRelProviders(
155 dom::Element
* aElement
, const nsAString
& aID
) {
156 dom::DocumentOrShadowRoot
* docOrShadowRoot
=
157 aElement
->GetUncomposedDocOrConnectedShadowRoot();
158 DependentIDsHashtable
* hash
=
159 mDependentIDsHashes
.GetOrInsertNew(docOrShadowRoot
);
161 return hash
->GetOrInsertNew(aID
);
164 inline void DocAccessible::RemoveRelProvidersIfEmpty(dom::Element
* aElement
,
165 const nsAString
& aID
) {
166 dom::DocumentOrShadowRoot
* docOrShadowRoot
=
167 aElement
->GetUncomposedDocOrConnectedShadowRoot();
168 DependentIDsHashtable
* hash
= mDependentIDsHashes
.Get(docOrShadowRoot
);
170 AttrRelProviders
* providers
= hash
->Get(aID
);
171 if (providers
&& providers
->Length() == 0) {
173 if (mDependentIDsHashes
.IsEmpty()) {
174 mDependentIDsHashes
.Remove(docOrShadowRoot
);
181 } // namespace mozilla