1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/accessible/src/base/AccIterator.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,398 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "AccIterator.h" 1.9 + 1.10 +#include "AccGroupInfo.h" 1.11 +#ifdef MOZ_XUL 1.12 +#include "XULTreeAccessible.h" 1.13 +#endif 1.14 + 1.15 +#include "mozilla/dom/Element.h" 1.16 + 1.17 +using namespace mozilla; 1.18 +using namespace mozilla::a11y; 1.19 + 1.20 +//////////////////////////////////////////////////////////////////////////////// 1.21 +// AccIterator 1.22 +//////////////////////////////////////////////////////////////////////////////// 1.23 + 1.24 +AccIterator::AccIterator(Accessible* aAccessible, 1.25 + filters::FilterFuncPtr aFilterFunc) : 1.26 + mFilterFunc(aFilterFunc) 1.27 +{ 1.28 + mState = new IteratorState(aAccessible); 1.29 +} 1.30 + 1.31 +AccIterator::~AccIterator() 1.32 +{ 1.33 + while (mState) { 1.34 + IteratorState *tmp = mState; 1.35 + mState = tmp->mParentState; 1.36 + delete tmp; 1.37 + } 1.38 +} 1.39 + 1.40 +Accessible* 1.41 +AccIterator::Next() 1.42 +{ 1.43 + while (mState) { 1.44 + Accessible* child = mState->mParent->GetChildAt(mState->mIndex++); 1.45 + if (!child) { 1.46 + IteratorState* tmp = mState; 1.47 + mState = mState->mParentState; 1.48 + delete tmp; 1.49 + 1.50 + continue; 1.51 + } 1.52 + 1.53 + uint32_t result = mFilterFunc(child); 1.54 + if (result & filters::eMatch) 1.55 + return child; 1.56 + 1.57 + if (!(result & filters::eSkipSubtree)) { 1.58 + IteratorState* childState = new IteratorState(child, mState); 1.59 + mState = childState; 1.60 + } 1.61 + } 1.62 + 1.63 + return nullptr; 1.64 +} 1.65 + 1.66 +//////////////////////////////////////////////////////////////////////////////// 1.67 +// nsAccIterator::IteratorState 1.68 + 1.69 +AccIterator::IteratorState::IteratorState(Accessible* aParent, 1.70 + IteratorState *mParentState) : 1.71 + mParent(aParent), mIndex(0), mParentState(mParentState) 1.72 +{ 1.73 +} 1.74 + 1.75 + 1.76 +//////////////////////////////////////////////////////////////////////////////// 1.77 +// RelatedAccIterator 1.78 +//////////////////////////////////////////////////////////////////////////////// 1.79 + 1.80 +RelatedAccIterator:: 1.81 + RelatedAccIterator(DocAccessible* aDocument, nsIContent* aDependentContent, 1.82 + nsIAtom* aRelAttr) : 1.83 + mDocument(aDocument), mRelAttr(aRelAttr), mProviders(nullptr), 1.84 + mBindingParent(nullptr), mIndex(0) 1.85 +{ 1.86 + mBindingParent = aDependentContent->GetBindingParent(); 1.87 + nsIAtom* IDAttr = mBindingParent ? 1.88 + nsGkAtoms::anonid : aDependentContent->GetIDAttributeName(); 1.89 + 1.90 + nsAutoString id; 1.91 + if (aDependentContent->GetAttr(kNameSpaceID_None, IDAttr, id)) 1.92 + mProviders = mDocument->mDependentIDsHash.Get(id); 1.93 +} 1.94 + 1.95 +Accessible* 1.96 +RelatedAccIterator::Next() 1.97 +{ 1.98 + if (!mProviders) 1.99 + return nullptr; 1.100 + 1.101 + while (mIndex < mProviders->Length()) { 1.102 + DocAccessible::AttrRelProvider* provider = (*mProviders)[mIndex++]; 1.103 + 1.104 + // Return related accessible for the given attribute and if the provider 1.105 + // content is in the same binding in the case of XBL usage. 1.106 + if (provider->mRelAttr == mRelAttr) { 1.107 + nsIContent* bindingParent = provider->mContent->GetBindingParent(); 1.108 + bool inScope = mBindingParent == bindingParent || 1.109 + mBindingParent == provider->mContent; 1.110 + 1.111 + if (inScope) { 1.112 + Accessible* related = mDocument->GetAccessible(provider->mContent); 1.113 + if (related) 1.114 + return related; 1.115 + 1.116 + // If the document content is pointed by relation then return the document 1.117 + // itself. 1.118 + if (provider->mContent == mDocument->GetContent()) 1.119 + return mDocument; 1.120 + } 1.121 + } 1.122 + } 1.123 + 1.124 + return nullptr; 1.125 +} 1.126 + 1.127 + 1.128 +//////////////////////////////////////////////////////////////////////////////// 1.129 +// HTMLLabelIterator 1.130 +//////////////////////////////////////////////////////////////////////////////// 1.131 + 1.132 +HTMLLabelIterator:: 1.133 + HTMLLabelIterator(DocAccessible* aDocument, const Accessible* aAccessible, 1.134 + LabelFilter aFilter) : 1.135 + mRelIter(aDocument, aAccessible->GetContent(), nsGkAtoms::_for), 1.136 + mAcc(aAccessible), mLabelFilter(aFilter) 1.137 +{ 1.138 +} 1.139 + 1.140 +Accessible* 1.141 +HTMLLabelIterator::Next() 1.142 +{ 1.143 + // Get either <label for="[id]"> element which explicitly points to given 1.144 + // element, or <label> ancestor which implicitly point to it. 1.145 + Accessible* label = nullptr; 1.146 + while ((label = mRelIter.Next())) { 1.147 + if (label->GetContent()->Tag() == nsGkAtoms::label) 1.148 + return label; 1.149 + } 1.150 + 1.151 + // Ignore ancestor label on not widget accessible. 1.152 + if (mLabelFilter == eSkipAncestorLabel || !mAcc->IsWidget()) 1.153 + return nullptr; 1.154 + 1.155 + // Go up tree to get a name of ancestor label if there is one (an ancestor 1.156 + // <label> implicitly points to us). Don't go up farther than form or 1.157 + // document. 1.158 + Accessible* walkUp = mAcc->Parent(); 1.159 + while (walkUp && !walkUp->IsDoc()) { 1.160 + nsIContent* walkUpElm = walkUp->GetContent(); 1.161 + if (walkUpElm->IsHTML()) { 1.162 + if (walkUpElm->Tag() == nsGkAtoms::label && 1.163 + !walkUpElm->HasAttr(kNameSpaceID_None, nsGkAtoms::_for)) { 1.164 + mLabelFilter = eSkipAncestorLabel; // prevent infinite loop 1.165 + return walkUp; 1.166 + } 1.167 + 1.168 + if (walkUpElm->Tag() == nsGkAtoms::form) 1.169 + break; 1.170 + } 1.171 + 1.172 + walkUp = walkUp->Parent(); 1.173 + } 1.174 + 1.175 + return nullptr; 1.176 +} 1.177 + 1.178 + 1.179 +//////////////////////////////////////////////////////////////////////////////// 1.180 +// HTMLOutputIterator 1.181 +//////////////////////////////////////////////////////////////////////////////// 1.182 + 1.183 +HTMLOutputIterator:: 1.184 +HTMLOutputIterator(DocAccessible* aDocument, nsIContent* aElement) : 1.185 + mRelIter(aDocument, aElement, nsGkAtoms::_for) 1.186 +{ 1.187 +} 1.188 + 1.189 +Accessible* 1.190 +HTMLOutputIterator::Next() 1.191 +{ 1.192 + Accessible* output = nullptr; 1.193 + while ((output = mRelIter.Next())) { 1.194 + if (output->GetContent()->Tag() == nsGkAtoms::output) 1.195 + return output; 1.196 + } 1.197 + 1.198 + return nullptr; 1.199 +} 1.200 + 1.201 + 1.202 +//////////////////////////////////////////////////////////////////////////////// 1.203 +// XULLabelIterator 1.204 +//////////////////////////////////////////////////////////////////////////////// 1.205 + 1.206 +XULLabelIterator:: 1.207 + XULLabelIterator(DocAccessible* aDocument, nsIContent* aElement) : 1.208 + mRelIter(aDocument, aElement, nsGkAtoms::control) 1.209 +{ 1.210 +} 1.211 + 1.212 +Accessible* 1.213 +XULLabelIterator::Next() 1.214 +{ 1.215 + Accessible* label = nullptr; 1.216 + while ((label = mRelIter.Next())) { 1.217 + if (label->GetContent()->Tag() == nsGkAtoms::label) 1.218 + return label; 1.219 + } 1.220 + 1.221 + return nullptr; 1.222 +} 1.223 + 1.224 + 1.225 +//////////////////////////////////////////////////////////////////////////////// 1.226 +// XULDescriptionIterator 1.227 +//////////////////////////////////////////////////////////////////////////////// 1.228 + 1.229 +XULDescriptionIterator:: 1.230 + XULDescriptionIterator(DocAccessible* aDocument, nsIContent* aElement) : 1.231 + mRelIter(aDocument, aElement, nsGkAtoms::control) 1.232 +{ 1.233 +} 1.234 + 1.235 +Accessible* 1.236 +XULDescriptionIterator::Next() 1.237 +{ 1.238 + Accessible* descr = nullptr; 1.239 + while ((descr = mRelIter.Next())) { 1.240 + if (descr->GetContent()->Tag() == nsGkAtoms::description) 1.241 + return descr; 1.242 + } 1.243 + 1.244 + return nullptr; 1.245 +} 1.246 + 1.247 +//////////////////////////////////////////////////////////////////////////////// 1.248 +// IDRefsIterator 1.249 +//////////////////////////////////////////////////////////////////////////////// 1.250 + 1.251 +IDRefsIterator:: 1.252 + IDRefsIterator(DocAccessible* aDoc, nsIContent* aContent, 1.253 + nsIAtom* aIDRefsAttr) : 1.254 + mContent(aContent), mDoc(aDoc), mCurrIdx(0) 1.255 +{ 1.256 + if (mContent->IsInDoc()) 1.257 + mContent->GetAttr(kNameSpaceID_None, aIDRefsAttr, mIDs); 1.258 +} 1.259 + 1.260 +const nsDependentSubstring 1.261 +IDRefsIterator::NextID() 1.262 +{ 1.263 + for (; mCurrIdx < mIDs.Length(); mCurrIdx++) { 1.264 + if (!NS_IsAsciiWhitespace(mIDs[mCurrIdx])) 1.265 + break; 1.266 + } 1.267 + 1.268 + if (mCurrIdx >= mIDs.Length()) 1.269 + return nsDependentSubstring(); 1.270 + 1.271 + nsAString::index_type idStartIdx = mCurrIdx; 1.272 + while (++mCurrIdx < mIDs.Length()) { 1.273 + if (NS_IsAsciiWhitespace(mIDs[mCurrIdx])) 1.274 + break; 1.275 + } 1.276 + 1.277 + return Substring(mIDs, idStartIdx, mCurrIdx++ - idStartIdx); 1.278 +} 1.279 + 1.280 +nsIContent* 1.281 +IDRefsIterator::NextElem() 1.282 +{ 1.283 + while (true) { 1.284 + const nsDependentSubstring id = NextID(); 1.285 + if (id.IsEmpty()) 1.286 + break; 1.287 + 1.288 + nsIContent* refContent = GetElem(id); 1.289 + if (refContent) 1.290 + return refContent; 1.291 + } 1.292 + 1.293 + return nullptr; 1.294 +} 1.295 + 1.296 +nsIContent* 1.297 +IDRefsIterator::GetElem(const nsDependentSubstring& aID) 1.298 +{ 1.299 + // Get elements in DOM tree by ID attribute if this is an explicit content. 1.300 + // In case of bound element check its anonymous subtree. 1.301 + if (!mContent->IsInAnonymousSubtree()) { 1.302 + dom::Element* refElm = mContent->OwnerDoc()->GetElementById(aID); 1.303 + if (refElm || !mContent->GetXBLBinding()) 1.304 + return refElm; 1.305 + } 1.306 + 1.307 + // If content is in anonymous subtree or an element having anonymous subtree 1.308 + // then use "anonid" attribute to get elements in anonymous subtree. 1.309 + 1.310 + // Check inside the binding the element is contained in. 1.311 + nsIContent* bindingParent = mContent->GetBindingParent(); 1.312 + if (bindingParent) { 1.313 + nsIContent* refElm = bindingParent->OwnerDoc()-> 1.314 + GetAnonymousElementByAttribute(bindingParent, nsGkAtoms::anonid, aID); 1.315 + 1.316 + if (refElm) 1.317 + return refElm; 1.318 + } 1.319 + 1.320 + // Check inside the binding of the element. 1.321 + if (mContent->GetXBLBinding()) { 1.322 + return mContent->OwnerDoc()-> 1.323 + GetAnonymousElementByAttribute(mContent, nsGkAtoms::anonid, aID); 1.324 + } 1.325 + 1.326 + return nullptr; 1.327 +} 1.328 + 1.329 +Accessible* 1.330 +IDRefsIterator::Next() 1.331 +{ 1.332 + nsIContent* nextElm = NextElem(); 1.333 + return nextElm ? mDoc->GetAccessible(nextElm) : nullptr; 1.334 +} 1.335 + 1.336 + 1.337 +//////////////////////////////////////////////////////////////////////////////// 1.338 +// SingleAccIterator 1.339 +//////////////////////////////////////////////////////////////////////////////// 1.340 + 1.341 +Accessible* 1.342 +SingleAccIterator::Next() 1.343 +{ 1.344 + nsRefPtr<Accessible> nextAcc; 1.345 + mAcc.swap(nextAcc); 1.346 + return (nextAcc && !nextAcc->IsDefunct()) ? nextAcc : nullptr; 1.347 +} 1.348 + 1.349 + 1.350 +//////////////////////////////////////////////////////////////////////////////// 1.351 +// ItemIterator 1.352 +//////////////////////////////////////////////////////////////////////////////// 1.353 + 1.354 +Accessible* 1.355 +ItemIterator::Next() 1.356 +{ 1.357 + if (mContainer) { 1.358 + mAnchor = AccGroupInfo::FirstItemOf(mContainer); 1.359 + mContainer = nullptr; 1.360 + return mAnchor; 1.361 + } 1.362 + 1.363 + return mAnchor ? (mAnchor = AccGroupInfo::NextItemTo(mAnchor)) : nullptr; 1.364 +} 1.365 + 1.366 + 1.367 +//////////////////////////////////////////////////////////////////////////////// 1.368 +// XULTreeItemIterator 1.369 +//////////////////////////////////////////////////////////////////////////////// 1.370 + 1.371 +XULTreeItemIterator::XULTreeItemIterator(XULTreeAccessible* aXULTree, 1.372 + nsITreeView* aTreeView, 1.373 + int32_t aRowIdx) : 1.374 + mXULTree(aXULTree), mTreeView(aTreeView), mRowCount(-1), 1.375 + mContainerLevel(-1), mCurrRowIdx(aRowIdx + 1) 1.376 +{ 1.377 + mTreeView->GetRowCount(&mRowCount); 1.378 + if (aRowIdx != -1) 1.379 + mTreeView->GetLevel(aRowIdx, &mContainerLevel); 1.380 +} 1.381 + 1.382 +Accessible* 1.383 +XULTreeItemIterator::Next() 1.384 +{ 1.385 + while (mCurrRowIdx < mRowCount) { 1.386 + int32_t level = 0; 1.387 + mTreeView->GetLevel(mCurrRowIdx, &level); 1.388 + 1.389 + if (level == mContainerLevel + 1) 1.390 + return mXULTree->GetTreeItemAccessible(mCurrRowIdx++); 1.391 + 1.392 + if (level <= mContainerLevel) { // got level up 1.393 + mCurrRowIdx = mRowCount; 1.394 + break; 1.395 + } 1.396 + 1.397 + mCurrRowIdx++; 1.398 + } 1.399 + 1.400 + return nullptr; 1.401 +}