Bug 1836881 [wpt PR 40389] - [css-flex] Include gaps in multiline row max-content...
[gecko.git] / accessible / base / AccIterator.cpp
blob41380d41a413a8f5d3aa8c62495b00ea946045f9
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "AccIterator.h"
7 #include "AccGroupInfo.h"
8 #include "DocAccessible-inl.h"
9 #include "XULTreeAccessible.h"
10 #include "nsAccUtils.h"
12 #include "mozilla/a11y/DocAccessibleParent.h"
13 #include "mozilla/dom/DocumentOrShadowRoot.h"
14 #include "mozilla/dom/HTMLLabelElement.h"
16 using namespace mozilla;
17 using namespace mozilla::a11y;
19 ////////////////////////////////////////////////////////////////////////////////
20 // AccIterator
21 ////////////////////////////////////////////////////////////////////////////////
23 AccIterator::AccIterator(const LocalAccessible* aAccessible,
24 filters::FilterFuncPtr aFilterFunc)
25 : mFilterFunc(aFilterFunc) {
26 mState = new IteratorState(aAccessible);
29 AccIterator::~AccIterator() {
30 while (mState) {
31 IteratorState* tmp = mState;
32 mState = tmp->mParentState;
33 delete tmp;
37 LocalAccessible* AccIterator::Next() {
38 while (mState) {
39 LocalAccessible* child = mState->mParent->LocalChildAt(mState->mIndex++);
40 if (!child) {
41 IteratorState* tmp = mState;
42 mState = mState->mParentState;
43 delete tmp;
45 continue;
48 uint32_t result = mFilterFunc(child);
49 if (result & filters::eMatch) return child;
51 if (!(result & filters::eSkipSubtree)) {
52 IteratorState* childState = new IteratorState(child, mState);
53 mState = childState;
57 return nullptr;
60 ////////////////////////////////////////////////////////////////////////////////
61 // nsAccIterator::IteratorState
63 AccIterator::IteratorState::IteratorState(const LocalAccessible* aParent,
64 IteratorState* mParentState)
65 : mParent(aParent), mIndex(0), mParentState(mParentState) {}
67 ////////////////////////////////////////////////////////////////////////////////
68 // RelatedAccIterator
69 ////////////////////////////////////////////////////////////////////////////////
71 RelatedAccIterator::RelatedAccIterator(DocAccessible* aDocument,
72 nsIContent* aDependentContent,
73 nsAtom* aRelAttr)
74 : mDocument(aDocument), mRelAttr(aRelAttr), mProviders(nullptr), mIndex(0) {
75 nsAutoString id;
76 if (aDependentContent->IsElement() &&
77 aDependentContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::id,
78 id)) {
79 mProviders = mDocument->GetRelProviders(aDependentContent->AsElement(), id);
83 LocalAccessible* RelatedAccIterator::Next() {
84 if (!mProviders) return nullptr;
86 while (mIndex < mProviders->Length()) {
87 const auto& provider = (*mProviders)[mIndex++];
89 // Return related accessible for the given attribute.
90 if (provider->mRelAttr == mRelAttr) {
91 LocalAccessible* related = mDocument->GetAccessible(provider->mContent);
92 if (related) {
93 return related;
96 // If the document content is pointed by relation then return the
97 // document itself.
98 if (provider->mContent == mDocument->GetContent()) {
99 return mDocument;
104 return nullptr;
107 ////////////////////////////////////////////////////////////////////////////////
108 // HTMLLabelIterator
109 ////////////////////////////////////////////////////////////////////////////////
111 HTMLLabelIterator::HTMLLabelIterator(DocAccessible* aDocument,
112 const LocalAccessible* aAccessible,
113 LabelFilter aFilter)
114 : mRelIter(aDocument, aAccessible->GetContent(), nsGkAtoms::_for),
115 mAcc(aAccessible),
116 mLabelFilter(aFilter) {}
118 bool HTMLLabelIterator::IsLabel(LocalAccessible* aLabel) {
119 dom::HTMLLabelElement* labelEl =
120 dom::HTMLLabelElement::FromNode(aLabel->GetContent());
121 return labelEl && labelEl->GetControl() == mAcc->GetContent();
124 LocalAccessible* HTMLLabelIterator::Next() {
125 // Get either <label for="[id]"> element which explicitly points to given
126 // element, or <label> ancestor which implicitly point to it.
127 LocalAccessible* label = nullptr;
128 while ((label = mRelIter.Next())) {
129 if (IsLabel(label)) {
130 return label;
134 // Ignore ancestor label on not widget accessible.
135 if (mLabelFilter == eSkipAncestorLabel || !mAcc->IsWidget()) return nullptr;
137 // Go up tree to get a name of ancestor label if there is one (an ancestor
138 // <label> implicitly points to us). Don't go up farther than form or
139 // document.
140 LocalAccessible* walkUp = mAcc->LocalParent();
141 while (walkUp && !walkUp->IsDoc()) {
142 nsIContent* walkUpEl = walkUp->GetContent();
143 if (IsLabel(walkUp) &&
144 !walkUpEl->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::_for)) {
145 mLabelFilter = eSkipAncestorLabel; // prevent infinite loop
146 return walkUp;
149 if (walkUpEl->IsHTMLElement(nsGkAtoms::form)) break;
151 walkUp = walkUp->LocalParent();
154 return nullptr;
157 ////////////////////////////////////////////////////////////////////////////////
158 // HTMLOutputIterator
159 ////////////////////////////////////////////////////////////////////////////////
161 HTMLOutputIterator::HTMLOutputIterator(DocAccessible* aDocument,
162 nsIContent* aElement)
163 : mRelIter(aDocument, aElement, nsGkAtoms::_for) {}
165 LocalAccessible* HTMLOutputIterator::Next() {
166 LocalAccessible* output = nullptr;
167 while ((output = mRelIter.Next())) {
168 if (output->GetContent()->IsHTMLElement(nsGkAtoms::output)) return output;
171 return nullptr;
174 ////////////////////////////////////////////////////////////////////////////////
175 // XULLabelIterator
176 ////////////////////////////////////////////////////////////////////////////////
178 XULLabelIterator::XULLabelIterator(DocAccessible* aDocument,
179 nsIContent* aElement)
180 : mRelIter(aDocument, aElement, nsGkAtoms::control) {}
182 LocalAccessible* XULLabelIterator::Next() {
183 LocalAccessible* label = nullptr;
184 while ((label = mRelIter.Next())) {
185 if (label->GetContent()->IsXULElement(nsGkAtoms::label)) return label;
188 return nullptr;
191 ////////////////////////////////////////////////////////////////////////////////
192 // XULDescriptionIterator
193 ////////////////////////////////////////////////////////////////////////////////
195 XULDescriptionIterator::XULDescriptionIterator(DocAccessible* aDocument,
196 nsIContent* aElement)
197 : mRelIter(aDocument, aElement, nsGkAtoms::control) {}
199 LocalAccessible* XULDescriptionIterator::Next() {
200 LocalAccessible* descr = nullptr;
201 while ((descr = mRelIter.Next())) {
202 if (descr->GetContent()->IsXULElement(nsGkAtoms::description)) return descr;
205 return nullptr;
208 ////////////////////////////////////////////////////////////////////////////////
209 // IDRefsIterator
210 ////////////////////////////////////////////////////////////////////////////////
212 IDRefsIterator::IDRefsIterator(DocAccessible* aDoc, nsIContent* aContent,
213 nsAtom* aIDRefsAttr)
214 : mContent(aContent), mDoc(aDoc), mCurrIdx(0) {
215 if (mContent->IsElement()) {
216 mContent->AsElement()->GetAttr(aIDRefsAttr, mIDs);
220 const nsDependentSubstring IDRefsIterator::NextID() {
221 for (; mCurrIdx < mIDs.Length(); mCurrIdx++) {
222 if (!NS_IsAsciiWhitespace(mIDs[mCurrIdx])) break;
225 if (mCurrIdx >= mIDs.Length()) return nsDependentSubstring();
227 nsAString::index_type idStartIdx = mCurrIdx;
228 while (++mCurrIdx < mIDs.Length()) {
229 if (NS_IsAsciiWhitespace(mIDs[mCurrIdx])) break;
232 return Substring(mIDs, idStartIdx, mCurrIdx++ - idStartIdx);
235 nsIContent* IDRefsIterator::NextElem() {
236 while (true) {
237 const nsDependentSubstring id = NextID();
238 if (id.IsEmpty()) break;
240 nsIContent* refContent = GetElem(id);
241 if (refContent) return refContent;
244 return nullptr;
247 dom::Element* IDRefsIterator::GetElem(nsIContent* aContent,
248 const nsAString& aID) {
249 // Get elements in DOM tree by ID attribute if this is an explicit content.
250 // In case of bound element check its anonymous subtree.
251 if (!aContent->IsInNativeAnonymousSubtree()) {
252 dom::DocumentOrShadowRoot* docOrShadowRoot =
253 aContent->GetUncomposedDocOrConnectedShadowRoot();
254 if (docOrShadowRoot) {
255 dom::Element* refElm = docOrShadowRoot->GetElementById(aID);
256 if (refElm) {
257 return refElm;
261 return nullptr;
264 dom::Element* IDRefsIterator::GetElem(const nsDependentSubstring& aID) {
265 return GetElem(mContent, aID);
268 LocalAccessible* IDRefsIterator::Next() {
269 nsIContent* nextEl = nullptr;
270 while ((nextEl = NextElem())) {
271 LocalAccessible* acc = mDoc->GetAccessible(nextEl);
272 if (acc) {
273 return acc;
276 return nullptr;
279 ////////////////////////////////////////////////////////////////////////////////
280 // SingleAccIterator
281 ////////////////////////////////////////////////////////////////////////////////
283 Accessible* SingleAccIterator::Next() {
284 Accessible* nextAcc = mAcc;
285 mAcc = nullptr;
286 if (!nextAcc) {
287 return nullptr;
290 MOZ_ASSERT(!nextAcc->IsLocal() || !nextAcc->AsLocal()->IsDefunct(),
291 "Iterator references defunct accessible?");
292 return nextAcc;
295 ////////////////////////////////////////////////////////////////////////////////
296 // ItemIterator
297 ////////////////////////////////////////////////////////////////////////////////
299 Accessible* ItemIterator::Next() {
300 if (mContainer) {
301 mAnchor = AccGroupInfo::FirstItemOf(mContainer);
302 mContainer = nullptr;
303 return mAnchor;
306 if (mAnchor) {
307 mAnchor = AccGroupInfo::NextItemTo(mAnchor);
310 return mAnchor;
313 ////////////////////////////////////////////////////////////////////////////////
314 // XULTreeItemIterator
315 ////////////////////////////////////////////////////////////////////////////////
317 XULTreeItemIterator::XULTreeItemIterator(const XULTreeAccessible* aXULTree,
318 nsITreeView* aTreeView,
319 int32_t aRowIdx)
320 : mXULTree(aXULTree),
321 mTreeView(aTreeView),
322 mRowCount(-1),
323 mContainerLevel(-1),
324 mCurrRowIdx(aRowIdx + 1) {
325 mTreeView->GetRowCount(&mRowCount);
326 if (aRowIdx != -1) mTreeView->GetLevel(aRowIdx, &mContainerLevel);
329 LocalAccessible* XULTreeItemIterator::Next() {
330 while (mCurrRowIdx < mRowCount) {
331 int32_t level = 0;
332 mTreeView->GetLevel(mCurrRowIdx, &level);
334 if (level == mContainerLevel + 1) {
335 return mXULTree->GetTreeItemAccessible(mCurrRowIdx++);
338 if (level <= mContainerLevel) { // got level up
339 mCurrRowIdx = mRowCount;
340 break;
343 mCurrRowIdx++;
346 return nullptr;
349 ////////////////////////////////////////////////////////////////////////////////
350 // RemoteAccIterator
351 ////////////////////////////////////////////////////////////////////////////////
353 Accessible* RemoteAccIterator::Next() {
354 while (mIndex < mIds.Length()) {
355 uint64_t id = mIds[mIndex++];
356 Accessible* acc = mDoc->GetAccessible(id);
357 if (acc) {
358 return acc;
361 return nullptr;