tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

AccIterator.cpp (13535B)


      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/. */
      4 
      5 #include "AccIterator.h"
      6 
      7 #include "AccGroupInfo.h"
      8 #include "ARIAMap.h"
      9 #include "DocAccessible-inl.h"
     10 #include "LocalAccessible-inl.h"
     11 #include "nsAccUtils.h"
     12 #include "XULTreeAccessible.h"
     13 
     14 #include "mozilla/a11y/DocAccessibleParent.h"
     15 #include "mozilla/dom/DocumentOrShadowRoot.h"
     16 #include "mozilla/dom/Element.h"
     17 #include "mozilla/dom/HTMLLabelElement.h"
     18 
     19 using namespace mozilla;
     20 using namespace mozilla::a11y;
     21 
     22 ////////////////////////////////////////////////////////////////////////////////
     23 // AccIterator
     24 ////////////////////////////////////////////////////////////////////////////////
     25 
     26 AccIterator::AccIterator(const LocalAccessible* aAccessible,
     27                         filters::FilterFuncPtr aFilterFunc)
     28    : mFilterFunc(aFilterFunc) {
     29  mState = new IteratorState(aAccessible);
     30 }
     31 
     32 AccIterator::~AccIterator() {
     33  while (mState) {
     34    IteratorState* tmp = mState;
     35    mState = tmp->mParentState;
     36    delete tmp;
     37  }
     38 }
     39 
     40 LocalAccessible* AccIterator::Next() {
     41  while (mState) {
     42    LocalAccessible* child = mState->mParent->LocalChildAt(mState->mIndex++);
     43    if (!child) {
     44      IteratorState* tmp = mState;
     45      mState = mState->mParentState;
     46      delete tmp;
     47 
     48      continue;
     49    }
     50 
     51    uint32_t result = mFilterFunc(child);
     52    if (result & filters::eMatch) return child;
     53 
     54    if (!(result & filters::eSkipSubtree)) {
     55      IteratorState* childState = new IteratorState(child, mState);
     56      mState = childState;
     57    }
     58  }
     59 
     60  return nullptr;
     61 }
     62 
     63 ////////////////////////////////////////////////////////////////////////////////
     64 // nsAccIterator::IteratorState
     65 
     66 AccIterator::IteratorState::IteratorState(const LocalAccessible* aParent,
     67                                          IteratorState* mParentState)
     68    : mParent(aParent), mIndex(0), mParentState(mParentState) {}
     69 
     70 ////////////////////////////////////////////////////////////////////////////////
     71 // RelatedAccIterator
     72 ////////////////////////////////////////////////////////////////////////////////
     73 
     74 RelatedAccIterator::RelatedAccIterator(DocAccessible* aDocument,
     75                                       nsIContent* aDependentContent,
     76                                       nsAtom* aRelAttr)
     77    : mDocument(aDocument),
     78      mDependentContent(aDependentContent),
     79      mRelAttr(aRelAttr),
     80      mProviders(nullptr),
     81      mIndex(0),
     82      mIsWalkingDependentElements(false) {
     83  nsAutoString id;
     84  if (aDependentContent->IsElement() &&
     85      aDependentContent->AsElement()->GetAttr(nsGkAtoms::id, id)) {
     86    mProviders = mDocument->GetRelProviders(aDependentContent->AsElement(), id);
     87  }
     88 }
     89 
     90 LocalAccessible* RelatedAccIterator::Next() {
     91  if (!mProviders || mIndex == mProviders->Length()) {
     92    if (mIsWalkingDependentElements) {
     93      // We've walked both dependent ids and dependent elements, so there are
     94      // no more targets.
     95      return nullptr;
     96    }
     97    // We've returned all dependent ids, but there might be dependent elements
     98    // too. Walk those next.
     99    mIsWalkingDependentElements = true;
    100    mIndex = 0;
    101    if (auto providers =
    102            mDocument->mDependentElementsMap.Lookup(mDependentContent)) {
    103      mProviders = &providers.Data();
    104    } else {
    105      mProviders = nullptr;
    106      return nullptr;
    107    }
    108  }
    109 
    110  while (mIndex < mProviders->Length()) {
    111    const auto& provider = (*mProviders)[mIndex++];
    112 
    113    // Return related accessible for the given attribute.
    114    if (mRelAttr && provider->mRelAttr != mRelAttr) {
    115      continue;
    116    }
    117    // If we're walking elements (not ids), the explicitly set attr-element
    118    // `mDependentContent` must be a descendant of any of the refering element
    119    // `mProvider->mContent`'s shadow-including ancestors.
    120    if (mIsWalkingDependentElements &&
    121        !nsCoreUtils::IsDescendantOfAnyShadowIncludingAncestor(
    122            mDependentContent, provider->mContent)) {
    123      continue;
    124    }
    125    LocalAccessible* related = mDocument->GetAccessible(provider->mContent);
    126    if (related) {
    127      return related;
    128    }
    129 
    130    // If the document content is pointed by relation then return the
    131    // document itself.
    132    if (provider->mContent == mDocument->GetContent()) {
    133      return mDocument;
    134    }
    135  }
    136 
    137  // We exhausted mProviders without returning anything.
    138  if (!mIsWalkingDependentElements) {
    139    // Call this function again to start walking the dependent elements.
    140    return Next();
    141  }
    142  return nullptr;
    143 }
    144 
    145 ////////////////////////////////////////////////////////////////////////////////
    146 // HTMLLabelIterator
    147 ////////////////////////////////////////////////////////////////////////////////
    148 
    149 HTMLLabelIterator::HTMLLabelIterator(DocAccessible* aDocument,
    150                                     const LocalAccessible* aAccessible,
    151                                     LabelFilter aFilter)
    152    : mRelIter(aDocument, aAccessible->GetContent(), nsGkAtoms::_for),
    153      mAcc(aAccessible),
    154      mLabelFilter(aFilter) {}
    155 
    156 bool HTMLLabelIterator::IsLabel(LocalAccessible* aLabel) {
    157  dom::HTMLLabelElement* labelEl =
    158      dom::HTMLLabelElement::FromNode(aLabel->GetContent());
    159  return labelEl && labelEl->GetControl() == mAcc->GetContent();
    160 }
    161 
    162 LocalAccessible* HTMLLabelIterator::Next() {
    163  // Get either <label for="[id]"> element which explicitly points to given
    164  // element, or <label> ancestor which implicitly point to it.
    165  LocalAccessible* label = nullptr;
    166  while ((label = mRelIter.Next())) {
    167    if (IsLabel(label)) {
    168      return label;
    169    }
    170  }
    171 
    172  // Ignore ancestor label on not widget accessible.
    173  if (mLabelFilter == eSkipAncestorLabel || !mAcc->IsWidget()) return nullptr;
    174 
    175  // Go up tree to get a name of ancestor label if there is one (an ancestor
    176  // <label> implicitly points to us). Don't go up farther than form or
    177  // document.
    178  LocalAccessible* walkUp = mAcc->LocalParent();
    179  while (walkUp && !walkUp->IsDoc()) {
    180    nsIContent* walkUpEl = walkUp->GetContent();
    181    if (IsLabel(walkUp) && !walkUpEl->AsElement()->HasAttr(nsGkAtoms::_for)) {
    182      mLabelFilter = eSkipAncestorLabel;  // prevent infinite loop
    183      return walkUp;
    184    }
    185 
    186    if (walkUpEl->IsHTMLElement(nsGkAtoms::form)) break;
    187 
    188    walkUp = walkUp->LocalParent();
    189  }
    190 
    191  return nullptr;
    192 }
    193 
    194 ////////////////////////////////////////////////////////////////////////////////
    195 // HTMLOutputIterator
    196 ////////////////////////////////////////////////////////////////////////////////
    197 
    198 HTMLOutputIterator::HTMLOutputIterator(DocAccessible* aDocument,
    199                                       nsIContent* aElement)
    200    : mRelIter(aDocument, aElement, nsGkAtoms::_for) {}
    201 
    202 LocalAccessible* HTMLOutputIterator::Next() {
    203  LocalAccessible* output = nullptr;
    204  while ((output = mRelIter.Next())) {
    205    if (output->GetContent()->IsHTMLElement(nsGkAtoms::output)) return output;
    206  }
    207 
    208  return nullptr;
    209 }
    210 
    211 ////////////////////////////////////////////////////////////////////////////////
    212 // XULLabelIterator
    213 ////////////////////////////////////////////////////////////////////////////////
    214 
    215 XULLabelIterator::XULLabelIterator(DocAccessible* aDocument,
    216                                   nsIContent* aElement)
    217    : mRelIter(aDocument, aElement, nsGkAtoms::control) {}
    218 
    219 LocalAccessible* XULLabelIterator::Next() {
    220  LocalAccessible* label = nullptr;
    221  while ((label = mRelIter.Next())) {
    222    if (label->GetContent()->IsXULElement(nsGkAtoms::label)) return label;
    223  }
    224 
    225  return nullptr;
    226 }
    227 
    228 ////////////////////////////////////////////////////////////////////////////////
    229 // XULDescriptionIterator
    230 ////////////////////////////////////////////////////////////////////////////////
    231 
    232 XULDescriptionIterator::XULDescriptionIterator(DocAccessible* aDocument,
    233                                               nsIContent* aElement)
    234    : mRelIter(aDocument, aElement, nsGkAtoms::control) {}
    235 
    236 LocalAccessible* XULDescriptionIterator::Next() {
    237  LocalAccessible* descr = nullptr;
    238  while ((descr = mRelIter.Next())) {
    239    if (descr->GetContent()->IsXULElement(nsGkAtoms::description)) return descr;
    240  }
    241 
    242  return nullptr;
    243 }
    244 
    245 ////////////////////////////////////////////////////////////////////////////////
    246 // AssociatedElementsIterator
    247 ////////////////////////////////////////////////////////////////////////////////
    248 
    249 AssociatedElementsIterator::AssociatedElementsIterator(DocAccessible* aDoc,
    250                                                       nsIContent* aContent,
    251                                                       nsAtom* aIDRefsAttr)
    252    : mContent(aContent), mDoc(aDoc), mCurrIdx(0), mElemIdx(0) {
    253  if (mContent->IsElement()) {
    254    mContent->AsElement()->GetAttr(aIDRefsAttr, mIDs);
    255    if (mIDs.IsEmpty() &&
    256        (aria::AttrCharacteristicsFor(aIDRefsAttr) & ATTR_REFLECT_ELEMENTS)) {
    257      nsAccUtils::GetARIAElementsAttr(mContent->AsElement(), aIDRefsAttr,
    258                                      mElements);
    259    }
    260  }
    261 }
    262 
    263 const nsDependentSubstring AssociatedElementsIterator::NextID() {
    264  for (; mCurrIdx < mIDs.Length(); mCurrIdx++) {
    265    if (!NS_IsAsciiWhitespace(mIDs[mCurrIdx])) break;
    266  }
    267 
    268  if (mCurrIdx >= mIDs.Length()) return nsDependentSubstring();
    269 
    270  nsAString::index_type idStartIdx = mCurrIdx;
    271  while (++mCurrIdx < mIDs.Length()) {
    272    if (NS_IsAsciiWhitespace(mIDs[mCurrIdx])) break;
    273  }
    274 
    275  return Substring(mIDs, idStartIdx, mCurrIdx++ - idStartIdx);
    276 }
    277 
    278 dom::Element* AssociatedElementsIterator::NextElem() {
    279  while (true) {
    280    const nsDependentSubstring id = NextID();
    281    if (id.IsEmpty()) break;
    282 
    283    dom::Element* refContent = GetElem(id);
    284    if (refContent) return refContent;
    285  }
    286 
    287  while (dom::Element* element = mElements.SafeElementAt(mElemIdx++)) {
    288    if (nsCoreUtils::IsDescendantOfAnyShadowIncludingAncestor(element,
    289                                                              mContent)) {
    290      return element;
    291    }
    292  }
    293 
    294  return nullptr;
    295 }
    296 
    297 dom::Element* AssociatedElementsIterator::GetElem(nsIContent* aContent,
    298                                                  const nsAString& aID) {
    299  // Get elements in DOM tree by ID attribute if this is an explicit content.
    300  // In case of bound element check its anonymous subtree.
    301  if (!aContent->IsInNativeAnonymousSubtree()) {
    302    dom::DocumentOrShadowRoot* docOrShadowRoot =
    303        aContent->GetUncomposedDocOrConnectedShadowRoot();
    304    if (docOrShadowRoot) {
    305      dom::Element* refElm = docOrShadowRoot->GetElementById(aID);
    306      if (refElm) {
    307        return refElm;
    308      }
    309    }
    310  }
    311  return nullptr;
    312 }
    313 
    314 dom::Element* AssociatedElementsIterator::GetElem(
    315    const nsDependentSubstring& aID) {
    316  return GetElem(mContent, aID);
    317 }
    318 
    319 LocalAccessible* AssociatedElementsIterator::Next() {
    320  dom::Element* nextEl = nullptr;
    321  while ((nextEl = NextElem())) {
    322    LocalAccessible* acc = mDoc->GetAccessible(nextEl);
    323    if (acc) {
    324      return acc;
    325    }
    326  }
    327  return nullptr;
    328 }
    329 
    330 ////////////////////////////////////////////////////////////////////////////////
    331 // SingleAccIterator
    332 ////////////////////////////////////////////////////////////////////////////////
    333 
    334 Accessible* SingleAccIterator::Next() {
    335  Accessible* nextAcc = mAcc;
    336  mAcc = nullptr;
    337  if (!nextAcc) {
    338    return nullptr;
    339  }
    340 
    341  MOZ_ASSERT(!nextAcc->IsLocal() || !nextAcc->AsLocal()->IsDefunct(),
    342             "Iterator references defunct accessible?");
    343  return nextAcc;
    344 }
    345 
    346 ////////////////////////////////////////////////////////////////////////////////
    347 // ItemIterator
    348 ////////////////////////////////////////////////////////////////////////////////
    349 
    350 Accessible* ItemIterator::Next() {
    351  if (mContainer) {
    352    mAnchor = AccGroupInfo::FirstItemOf(mContainer);
    353    mContainer = nullptr;
    354    return mAnchor;
    355  }
    356 
    357  if (mAnchor) {
    358    mAnchor = AccGroupInfo::NextItemTo(mAnchor);
    359  }
    360 
    361  return mAnchor;
    362 }
    363 
    364 ////////////////////////////////////////////////////////////////////////////////
    365 // XULTreeItemIterator
    366 ////////////////////////////////////////////////////////////////////////////////
    367 
    368 XULTreeItemIterator::XULTreeItemIterator(const XULTreeAccessible* aXULTree,
    369                                         nsITreeView* aTreeView,
    370                                         int32_t aRowIdx)
    371    : mXULTree(aXULTree),
    372      mTreeView(aTreeView),
    373      mRowCount(-1),
    374      mContainerLevel(-1),
    375      mCurrRowIdx(aRowIdx + 1) {
    376  mTreeView->GetRowCount(&mRowCount);
    377  if (aRowIdx != -1) mTreeView->GetLevel(aRowIdx, &mContainerLevel);
    378 }
    379 
    380 LocalAccessible* XULTreeItemIterator::Next() {
    381  while (mCurrRowIdx < mRowCount) {
    382    int32_t level = 0;
    383    mTreeView->GetLevel(mCurrRowIdx, &level);
    384 
    385    if (level == mContainerLevel + 1) {
    386      return mXULTree->GetTreeItemAccessible(mCurrRowIdx++);
    387    }
    388 
    389    if (level <= mContainerLevel) {  // got level up
    390      mCurrRowIdx = mRowCount;
    391      break;
    392    }
    393 
    394    mCurrRowIdx++;
    395  }
    396 
    397  return nullptr;
    398 }
    399 
    400 ////////////////////////////////////////////////////////////////////////////////
    401 // RemoteAccIterator
    402 ////////////////////////////////////////////////////////////////////////////////
    403 
    404 Accessible* RemoteAccIterator::Next() {
    405  while (mIndex < mIds.Length()) {
    406    uint64_t id = mIds[mIndex++];
    407    Accessible* acc = mDoc->GetAccessible(id);
    408    if (acc) {
    409      return acc;
    410    }
    411  }
    412  return nullptr;
    413 }
    414 
    415 ////////////////////////////////////////////////////////////////////////////////
    416 // ArrayAccIterator
    417 ////////////////////////////////////////////////////////////////////////////////
    418 
    419 Accessible* ArrayAccIterator::Next() {
    420  if (mIndex < mAccs.Length()) {
    421    return mAccs[mIndex++];
    422  }
    423  return nullptr;
    424 }