accessible/src/base/AccIterator.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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 #ifdef MOZ_XUL
     9 #include "XULTreeAccessible.h"
    10 #endif
    12 #include "mozilla/dom/Element.h"
    14 using namespace mozilla;
    15 using namespace mozilla::a11y;
    17 ////////////////////////////////////////////////////////////////////////////////
    18 // AccIterator
    19 ////////////////////////////////////////////////////////////////////////////////
    21 AccIterator::AccIterator(Accessible* aAccessible,
    22                          filters::FilterFuncPtr aFilterFunc) :
    23   mFilterFunc(aFilterFunc)
    24 {
    25   mState = new IteratorState(aAccessible);
    26 }
    28 AccIterator::~AccIterator()
    29 {
    30   while (mState) {
    31     IteratorState *tmp = mState;
    32     mState = tmp->mParentState;
    33     delete tmp;
    34   }
    35 }
    37 Accessible*
    38 AccIterator::Next()
    39 {
    40   while (mState) {
    41     Accessible* child = mState->mParent->GetChildAt(mState->mIndex++);
    42     if (!child) {
    43       IteratorState* tmp = mState;
    44       mState = mState->mParentState;
    45       delete tmp;
    47       continue;
    48     }
    50     uint32_t result = mFilterFunc(child);
    51     if (result & filters::eMatch)
    52       return child;
    54     if (!(result & filters::eSkipSubtree)) {
    55       IteratorState* childState = new IteratorState(child, mState);
    56       mState = childState;
    57     }
    58   }
    60   return nullptr;
    61 }
    63 ////////////////////////////////////////////////////////////////////////////////
    64 // nsAccIterator::IteratorState
    66 AccIterator::IteratorState::IteratorState(Accessible* aParent,
    67                                           IteratorState *mParentState) :
    68   mParent(aParent), mIndex(0), mParentState(mParentState)
    69 {
    70 }
    73 ////////////////////////////////////////////////////////////////////////////////
    74 // RelatedAccIterator
    75 ////////////////////////////////////////////////////////////////////////////////
    77 RelatedAccIterator::
    78   RelatedAccIterator(DocAccessible* aDocument, nsIContent* aDependentContent,
    79                      nsIAtom* aRelAttr) :
    80   mDocument(aDocument), mRelAttr(aRelAttr), mProviders(nullptr),
    81   mBindingParent(nullptr), mIndex(0)
    82 {
    83   mBindingParent = aDependentContent->GetBindingParent();
    84   nsIAtom* IDAttr = mBindingParent ?
    85     nsGkAtoms::anonid : aDependentContent->GetIDAttributeName();
    87   nsAutoString id;
    88   if (aDependentContent->GetAttr(kNameSpaceID_None, IDAttr, id))
    89     mProviders = mDocument->mDependentIDsHash.Get(id);
    90 }
    92 Accessible*
    93 RelatedAccIterator::Next()
    94 {
    95   if (!mProviders)
    96     return nullptr;
    98   while (mIndex < mProviders->Length()) {
    99     DocAccessible::AttrRelProvider* provider = (*mProviders)[mIndex++];
   101     // Return related accessible for the given attribute and if the provider
   102     // content is in the same binding in the case of XBL usage.
   103     if (provider->mRelAttr == mRelAttr) {
   104       nsIContent* bindingParent = provider->mContent->GetBindingParent();
   105       bool inScope = mBindingParent == bindingParent ||
   106         mBindingParent == provider->mContent;
   108       if (inScope) {
   109         Accessible* related = mDocument->GetAccessible(provider->mContent);
   110         if (related)
   111           return related;
   113         // If the document content is pointed by relation then return the document
   114         // itself.
   115         if (provider->mContent == mDocument->GetContent())
   116           return mDocument;
   117       }
   118     }
   119   }
   121   return nullptr;
   122 }
   125 ////////////////////////////////////////////////////////////////////////////////
   126 // HTMLLabelIterator
   127 ////////////////////////////////////////////////////////////////////////////////
   129 HTMLLabelIterator::
   130   HTMLLabelIterator(DocAccessible* aDocument, const Accessible* aAccessible,
   131                     LabelFilter aFilter) :
   132   mRelIter(aDocument, aAccessible->GetContent(), nsGkAtoms::_for),
   133   mAcc(aAccessible), mLabelFilter(aFilter)
   134 {
   135 }
   137 Accessible*
   138 HTMLLabelIterator::Next()
   139 {
   140   // Get either <label for="[id]"> element which explicitly points to given
   141   // element, or <label> ancestor which implicitly point to it.
   142   Accessible* label = nullptr;
   143   while ((label = mRelIter.Next())) {
   144     if (label->GetContent()->Tag() == nsGkAtoms::label)
   145       return label;
   146   }
   148   // Ignore ancestor label on not widget accessible.
   149   if (mLabelFilter == eSkipAncestorLabel || !mAcc->IsWidget())
   150     return nullptr;
   152   // Go up tree to get a name of ancestor label if there is one (an ancestor
   153   // <label> implicitly points to us). Don't go up farther than form or
   154   // document.
   155   Accessible* walkUp = mAcc->Parent();
   156   while (walkUp && !walkUp->IsDoc()) {
   157     nsIContent* walkUpElm = walkUp->GetContent();
   158     if (walkUpElm->IsHTML()) {
   159       if (walkUpElm->Tag() == nsGkAtoms::label &&
   160           !walkUpElm->HasAttr(kNameSpaceID_None, nsGkAtoms::_for)) {
   161         mLabelFilter = eSkipAncestorLabel; // prevent infinite loop
   162         return walkUp;
   163       }
   165       if (walkUpElm->Tag() == nsGkAtoms::form)
   166         break;
   167     }
   169     walkUp = walkUp->Parent();
   170   }
   172   return nullptr;
   173 }
   176 ////////////////////////////////////////////////////////////////////////////////
   177 // HTMLOutputIterator
   178 ////////////////////////////////////////////////////////////////////////////////
   180 HTMLOutputIterator::
   181 HTMLOutputIterator(DocAccessible* aDocument, nsIContent* aElement) :
   182   mRelIter(aDocument, aElement, nsGkAtoms::_for)
   183 {
   184 }
   186 Accessible*
   187 HTMLOutputIterator::Next()
   188 {
   189   Accessible* output = nullptr;
   190   while ((output = mRelIter.Next())) {
   191     if (output->GetContent()->Tag() == nsGkAtoms::output)
   192       return output;
   193   }
   195   return nullptr;
   196 }
   199 ////////////////////////////////////////////////////////////////////////////////
   200 // XULLabelIterator
   201 ////////////////////////////////////////////////////////////////////////////////
   203 XULLabelIterator::
   204   XULLabelIterator(DocAccessible* aDocument, nsIContent* aElement) :
   205   mRelIter(aDocument, aElement, nsGkAtoms::control)
   206 {
   207 }
   209 Accessible*
   210 XULLabelIterator::Next()
   211 {
   212   Accessible* label = nullptr;
   213   while ((label = mRelIter.Next())) {
   214     if (label->GetContent()->Tag() == nsGkAtoms::label)
   215       return label;
   216   }
   218   return nullptr;
   219 }
   222 ////////////////////////////////////////////////////////////////////////////////
   223 // XULDescriptionIterator
   224 ////////////////////////////////////////////////////////////////////////////////
   226 XULDescriptionIterator::
   227   XULDescriptionIterator(DocAccessible* aDocument, nsIContent* aElement) :
   228   mRelIter(aDocument, aElement, nsGkAtoms::control)
   229 {
   230 }
   232 Accessible*
   233 XULDescriptionIterator::Next()
   234 {
   235   Accessible* descr = nullptr;
   236   while ((descr = mRelIter.Next())) {
   237     if (descr->GetContent()->Tag() == nsGkAtoms::description)
   238       return descr;
   239   }
   241   return nullptr;
   242 }
   244 ////////////////////////////////////////////////////////////////////////////////
   245 // IDRefsIterator
   246 ////////////////////////////////////////////////////////////////////////////////
   248 IDRefsIterator::
   249   IDRefsIterator(DocAccessible* aDoc, nsIContent* aContent,
   250                  nsIAtom* aIDRefsAttr) :
   251   mContent(aContent), mDoc(aDoc), mCurrIdx(0)
   252 {
   253   if (mContent->IsInDoc())
   254     mContent->GetAttr(kNameSpaceID_None, aIDRefsAttr, mIDs);
   255 }
   257 const nsDependentSubstring
   258 IDRefsIterator::NextID()
   259 {
   260   for (; mCurrIdx < mIDs.Length(); mCurrIdx++) {
   261     if (!NS_IsAsciiWhitespace(mIDs[mCurrIdx]))
   262       break;
   263   }
   265   if (mCurrIdx >= mIDs.Length())
   266     return nsDependentSubstring();
   268   nsAString::index_type idStartIdx = mCurrIdx;
   269   while (++mCurrIdx < mIDs.Length()) {
   270     if (NS_IsAsciiWhitespace(mIDs[mCurrIdx]))
   271       break;
   272   }
   274   return Substring(mIDs, idStartIdx, mCurrIdx++ - idStartIdx);
   275 }
   277 nsIContent*
   278 IDRefsIterator::NextElem()
   279 {
   280   while (true) {
   281     const nsDependentSubstring id = NextID();
   282     if (id.IsEmpty())
   283       break;
   285     nsIContent* refContent = GetElem(id);
   286     if (refContent)
   287       return refContent;
   288   }
   290   return nullptr;
   291 }
   293 nsIContent*
   294 IDRefsIterator::GetElem(const nsDependentSubstring& aID)
   295 {
   296   // Get elements in DOM tree by ID attribute if this is an explicit content.
   297   // In case of bound element check its anonymous subtree.
   298   if (!mContent->IsInAnonymousSubtree()) {
   299     dom::Element* refElm = mContent->OwnerDoc()->GetElementById(aID);
   300     if (refElm || !mContent->GetXBLBinding())
   301       return refElm;
   302   }
   304   // If content is in anonymous subtree or an element having anonymous subtree
   305   // then use "anonid" attribute to get elements in anonymous subtree.
   307   // Check inside the binding the element is contained in.
   308   nsIContent* bindingParent = mContent->GetBindingParent();
   309   if (bindingParent) {
   310     nsIContent* refElm = bindingParent->OwnerDoc()->
   311       GetAnonymousElementByAttribute(bindingParent, nsGkAtoms::anonid, aID);
   313     if (refElm)
   314       return refElm;
   315   }
   317   // Check inside the binding of the element.
   318   if (mContent->GetXBLBinding()) {
   319     return mContent->OwnerDoc()->
   320       GetAnonymousElementByAttribute(mContent, nsGkAtoms::anonid, aID);
   321   }
   323   return nullptr;
   324 }
   326 Accessible*
   327 IDRefsIterator::Next()
   328 {
   329   nsIContent* nextElm = NextElem();
   330   return nextElm ? mDoc->GetAccessible(nextElm) : nullptr;
   331 }
   334 ////////////////////////////////////////////////////////////////////////////////
   335 // SingleAccIterator
   336 ////////////////////////////////////////////////////////////////////////////////
   338 Accessible*
   339 SingleAccIterator::Next()
   340 {
   341   nsRefPtr<Accessible> nextAcc;
   342   mAcc.swap(nextAcc);
   343   return (nextAcc && !nextAcc->IsDefunct()) ? nextAcc : nullptr;
   344 }
   347 ////////////////////////////////////////////////////////////////////////////////
   348 // ItemIterator
   349 ////////////////////////////////////////////////////////////////////////////////
   351 Accessible*
   352 ItemIterator::Next()
   353 {
   354   if (mContainer) {
   355     mAnchor = AccGroupInfo::FirstItemOf(mContainer);
   356     mContainer = nullptr;
   357     return mAnchor;
   358   }
   360   return mAnchor ? (mAnchor = AccGroupInfo::NextItemTo(mAnchor)) : nullptr;
   361 }
   364 ////////////////////////////////////////////////////////////////////////////////
   365 // XULTreeItemIterator
   366 ////////////////////////////////////////////////////////////////////////////////
   368 XULTreeItemIterator::XULTreeItemIterator(XULTreeAccessible* aXULTree,
   369                                          nsITreeView* aTreeView,
   370                                          int32_t aRowIdx) :
   371   mXULTree(aXULTree), mTreeView(aTreeView), mRowCount(-1),
   372   mContainerLevel(-1), mCurrRowIdx(aRowIdx + 1)
   373 {
   374   mTreeView->GetRowCount(&mRowCount);
   375   if (aRowIdx != -1)
   376     mTreeView->GetLevel(aRowIdx, &mContainerLevel);
   377 }
   379 Accessible*
   380 XULTreeItemIterator::Next()
   381 {
   382   while (mCurrRowIdx < mRowCount) {
   383     int32_t level = 0;
   384     mTreeView->GetLevel(mCurrRowIdx, &level);
   386     if (level == mContainerLevel + 1)
   387       return mXULTree->GetTreeItemAccessible(mCurrRowIdx++);
   389     if (level <= mContainerLevel) { // got level up
   390       mCurrRowIdx = mRowCount;
   391       break;
   392     }
   394     mCurrRowIdx++;
   395   }
   397   return nullptr;
   398 }

mercurial