accessible/src/base/AccGroupInfo.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 "AccGroupInfo.h"
     6 #include "nsAccUtils.h"
     8 #include "Role.h"
     9 #include "States.h"
    11 using namespace mozilla::a11y;
    13 AccGroupInfo::AccGroupInfo(Accessible* aItem, role aRole) :
    14   mPosInSet(0), mSetSize(0), mParent(nullptr), mItem(aItem), mRole(aRole)
    15 {
    16   MOZ_COUNT_CTOR(AccGroupInfo);
    17   Update();
    18 }
    20 void
    21 AccGroupInfo::Update()
    22 {
    23   Accessible* parent = mItem->Parent();
    24   if (!parent)
    25     return;
    27   int32_t indexInParent = mItem->IndexInParent();
    28   uint32_t siblingCount = parent->ChildCount();
    29   if (indexInParent == -1 ||
    30       indexInParent >= static_cast<int32_t>(siblingCount)) {
    31     NS_ERROR("Wrong index in parent! Tree invalidation problem.");
    32     return;
    33   }
    35   int32_t level = nsAccUtils::GetARIAOrDefaultLevel(mItem);
    37   // Compute position in set.
    38   mPosInSet = 1;
    39   for (int32_t idx = indexInParent - 1; idx >= 0 ; idx--) {
    40     Accessible* sibling = parent->GetChildAt(idx);
    41     roles::Role siblingRole = sibling->Role();
    43     // If the sibling is separator then the group is ended.
    44     if (siblingRole == roles::SEPARATOR)
    45       break;
    47     // If sibling is not visible and hasn't the same base role.
    48     if (BaseRole(siblingRole) != mRole || sibling->State() & states::INVISIBLE)
    49       continue;
    51     // Check if it's hierarchical flatten structure, i.e. if the sibling
    52     // level is lesser than this one then group is ended, if the sibling level
    53     // is greater than this one then the group is split by some child elements
    54     // (group will be continued).
    55     int32_t siblingLevel = nsAccUtils::GetARIAOrDefaultLevel(sibling);
    56     if (siblingLevel < level) {
    57       mParent = sibling;
    58       break;
    59     }
    61     // Skip subset.
    62     if (siblingLevel > level)
    63       continue;
    65     // If the previous item in the group has calculated group information then
    66     // build group information for this item based on found one.
    67     if (sibling->mGroupInfo) {
    68       mPosInSet += sibling->mGroupInfo->mPosInSet;
    69       mParent = sibling->mGroupInfo->mParent;
    70       mSetSize = sibling->mGroupInfo->mSetSize;
    71       return;
    72     }
    74     mPosInSet++;
    75   }
    77   // Compute set size.
    78   mSetSize = mPosInSet;
    80   for (uint32_t idx = indexInParent + 1; idx < siblingCount; idx++) {
    81     Accessible* sibling = parent->GetChildAt(idx);
    83     roles::Role siblingRole = sibling->Role();
    85     // If the sibling is separator then the group is ended.
    86     if (siblingRole == roles::SEPARATOR)
    87       break;
    89     // If sibling is visible and has the same base role
    90     if (BaseRole(siblingRole) != mRole || sibling->State() & states::INVISIBLE)
    91       continue;
    93     // and check if it's hierarchical flatten structure.
    94     int32_t siblingLevel = nsAccUtils::GetARIAOrDefaultLevel(sibling);
    95     if (siblingLevel < level)
    96       break;
    98     // Skip subset.
    99     if (siblingLevel > level)
   100       continue;
   102     // If the next item in the group has calculated group information then
   103     // build group information for this item based on found one.
   104     if (sibling->mGroupInfo) {
   105       mParent = sibling->mGroupInfo->mParent;
   106       mSetSize = sibling->mGroupInfo->mSetSize;
   107       return;
   108     }
   110     mSetSize++;
   111   }
   113   if (mParent)
   114     return;
   116   roles::Role parentRole = parent->Role();
   117   if (ShouldReportRelations(mRole, parentRole))
   118     mParent = parent;
   120   // ARIA tree and list can be arranged by using ARIA groups to organize levels.
   121   if (parentRole != roles::GROUPING)
   122     return;
   124   // Way #1 for ARIA tree (not ARIA treegrid): previous sibling of a group is a
   125   // parent. In other words the parent of the tree item will be a group and
   126   // the previous tree item of the group is a conceptual parent of the tree
   127   // item.
   128   if (mRole == roles::OUTLINEITEM) {
   129     Accessible* parentPrevSibling = parent->PrevSibling();
   130     if (parentPrevSibling && parentPrevSibling->Role() == mRole) {
   131       mParent = parentPrevSibling;
   132       return;
   133     }
   134   }
   136   // Way #2 for ARIA list and tree: group is a child of an item. In other words
   137   // the parent of the item will be a group and containing item of the group is
   138   // a conceptual parent of the item.
   139   if (mRole == roles::LISTITEM || mRole == roles::OUTLINEITEM) {
   140     Accessible* grandParent = parent->Parent();
   141     if (grandParent && grandParent->Role() == mRole)
   142       mParent = grandParent;
   143   }
   144 }
   146 Accessible*
   147 AccGroupInfo::FirstItemOf(Accessible* aContainer)
   148 {
   149   // ARIA tree can be arranged by ARIA groups case #1 (previous sibling of a
   150   // group is a parent) or by aria-level.
   151   a11y::role containerRole = aContainer->Role();
   152   Accessible* item = aContainer->NextSibling();
   153   if (item) {
   154     if (containerRole == roles::OUTLINEITEM && item->Role() == roles::GROUPING)
   155       item = item->FirstChild();
   157     if (item) {
   158       AccGroupInfo* itemGroupInfo = item->GetGroupInfo();
   159       if (itemGroupInfo && itemGroupInfo->ConceptualParent() == aContainer)
   160         return item;
   161     }
   162   }
   164   // ARIA list and tree can be arranged by ARIA groups case #2 (group is
   165   // a child of an item).
   166   item = aContainer->LastChild();
   167   if (!item)
   168     return nullptr;
   170   if (item->Role() == roles::GROUPING &&
   171       (containerRole == roles::LISTITEM || containerRole == roles::OUTLINEITEM)) {
   172     item = item->FirstChild();
   173     if (item) {
   174       AccGroupInfo* itemGroupInfo = item->GetGroupInfo();
   175       if (itemGroupInfo && itemGroupInfo->ConceptualParent() == aContainer)
   176         return item;
   177     }
   178   }
   180   // Otherwise, it can be a direct child if the container is a list or tree.
   181   item = aContainer->FirstChild();
   182   if (ShouldReportRelations(item->Role(), containerRole))
   183     return item;
   185   return nullptr;
   186 }
   188 Accessible*
   189 AccGroupInfo::NextItemTo(Accessible* aItem)
   190 {
   191   AccGroupInfo* groupInfo = aItem->GetGroupInfo();
   192   if (!groupInfo)
   193     return nullptr;
   195   // If the item in middle of the group then search next item in siblings.
   196   if (groupInfo->PosInSet() >= groupInfo->SetSize())
   197     return nullptr;
   199   Accessible* parent = aItem->Parent();
   200   uint32_t childCount = parent->ChildCount();
   201   for (int32_t idx = aItem->IndexInParent() + 1; idx < childCount; idx++) {
   202     Accessible* nextItem = parent->GetChildAt(idx);
   203     AccGroupInfo* nextGroupInfo = nextItem->GetGroupInfo();
   204     if (nextGroupInfo &&
   205         nextGroupInfo->ConceptualParent() == groupInfo->ConceptualParent()) {
   206       return nextItem;
   207     }
   208   }
   210   NS_NOTREACHED("Item in the middle of the group but there's no next item!");
   211   return nullptr;
   212 }
   214 bool
   215 AccGroupInfo::ShouldReportRelations(role aRole, role aParentRole)
   216 {
   217   // We only want to report hierarchy-based node relations for items in tree or
   218   // list form.  ARIA level/owns relations are always reported.
   219   if (aParentRole == roles::OUTLINE && aRole == roles::OUTLINEITEM)
   220     return true;
   221   if (aParentRole == roles::TREE_TABLE && aRole == roles::ROW)
   222     return true;
   223   if (aParentRole == roles::LIST && aRole == roles::LISTITEM)
   224     return true;
   226   return false;
   227 }

mercurial