/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "AccIterator.h" #include "AccGroupInfo.h" #include "DocAccessible-inl.h" #include "XULTreeAccessible.h" #include "nsAccUtils.h" #include "mozilla/a11y/DocAccessibleParent.h" #include "mozilla/dom/DocumentOrShadowRoot.h" #include "mozilla/dom/HTMLLabelElement.h" #include "mozilla/StaticPrefs_accessibility.h" using namespace mozilla; using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// // AccIterator //////////////////////////////////////////////////////////////////////////////// AccIterator::AccIterator(const LocalAccessible* aAccessible, filters::FilterFuncPtr aFilterFunc) : mFilterFunc(aFilterFunc) { mState = new IteratorState(aAccessible); } AccIterator::~AccIterator() { while (mState) { IteratorState* tmp = mState; mState = tmp->mParentState; delete tmp; } } LocalAccessible* AccIterator::Next() { while (mState) { LocalAccessible* child = mState->mParent->LocalChildAt(mState->mIndex++); if (!child) { IteratorState* tmp = mState; mState = mState->mParentState; delete tmp; continue; } uint32_t result = mFilterFunc(child); if (result & filters::eMatch) return child; if (!(result & filters::eSkipSubtree)) { IteratorState* childState = new IteratorState(child, mState); mState = childState; } } return nullptr; } //////////////////////////////////////////////////////////////////////////////// // nsAccIterator::IteratorState AccIterator::IteratorState::IteratorState(const LocalAccessible* aParent, IteratorState* mParentState) : mParent(aParent), mIndex(0), mParentState(mParentState) {} //////////////////////////////////////////////////////////////////////////////// // RelatedAccIterator //////////////////////////////////////////////////////////////////////////////// RelatedAccIterator::RelatedAccIterator(DocAccessible* aDocument, nsIContent* aDependentContent, nsAtom* aRelAttr) : mDocument(aDocument), mRelAttr(aRelAttr), mProviders(nullptr), mIndex(0) { nsAutoString id; if (aDependentContent->IsElement() && aDependentContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id)) { mProviders = mDocument->GetRelProviders(aDependentContent->AsElement(), id); } } LocalAccessible* RelatedAccIterator::Next() { if (!mProviders) return nullptr; while (mIndex < mProviders->Length()) { const auto& provider = (*mProviders)[mIndex++]; // Return related accessible for the given attribute. if (provider->mRelAttr == mRelAttr) { LocalAccessible* related = mDocument->GetAccessible(provider->mContent); if (related) { return related; } // If the document content is pointed by relation then return the // document itself. if (provider->mContent == mDocument->GetContent()) { return mDocument; } } } return nullptr; } //////////////////////////////////////////////////////////////////////////////// // HTMLLabelIterator //////////////////////////////////////////////////////////////////////////////// HTMLLabelIterator::HTMLLabelIterator(DocAccessible* aDocument, const LocalAccessible* aAccessible, LabelFilter aFilter) : mRelIter(aDocument, aAccessible->GetContent(), nsGkAtoms::_for), mAcc(aAccessible), mLabelFilter(aFilter) {} bool HTMLLabelIterator::IsLabel(LocalAccessible* aLabel) { dom::HTMLLabelElement* labelEl = dom::HTMLLabelElement::FromNode(aLabel->GetContent()); return labelEl && labelEl->GetControl() == mAcc->GetContent(); } LocalAccessible* HTMLLabelIterator::Next() { // Get either