accessible/src/generic/ARIAGridAccessible.cpp

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "ARIAGridAccessible-inl.h"
     8 #include "Accessible-inl.h"
     9 #include "AccIterator.h"
    10 #include "nsAccUtils.h"
    11 #include "Role.h"
    12 #include "States.h"
    14 #include "nsIMutableArray.h"
    15 #include "nsIPersistentProperties2.h"
    16 #include "nsComponentManagerUtils.h"
    18 using namespace mozilla;
    19 using namespace mozilla::a11y;
    21 ////////////////////////////////////////////////////////////////////////////////
    22 // ARIAGridAccessible
    23 ////////////////////////////////////////////////////////////////////////////////
    26 ////////////////////////////////////////////////////////////////////////////////
    27 // Constructor
    29 ARIAGridAccessible::
    30   ARIAGridAccessible(nsIContent* aContent, DocAccessible* aDoc) :
    31   AccessibleWrap(aContent, aDoc), xpcAccessibleTable(this)
    32 {
    33 }
    35 ////////////////////////////////////////////////////////////////////////////////
    36 // nsISupports
    38 NS_IMPL_ISUPPORTS_INHERITED(ARIAGridAccessible,
    39                             Accessible,
    40                             nsIAccessibleTable)
    42 ////////////////////////////////////////////////////////////////////////////////
    43 // Accessible
    45 void
    46 ARIAGridAccessible::Shutdown()
    47 {
    48   mTable = nullptr;
    49   AccessibleWrap::Shutdown();
    50 }
    52 ////////////////////////////////////////////////////////////////////////////////
    53 // nsIAccessibleTable
    55 uint32_t
    56 ARIAGridAccessible::ColCount()
    57 {
    58   AccIterator rowIter(this, filters::GetRow);
    59   Accessible* row = rowIter.Next();
    60   if (!row)
    61     return 0;
    63   AccIterator cellIter(row, filters::GetCell);
    64   Accessible* cell = nullptr;
    66   uint32_t colCount = 0;
    67   while ((cell = cellIter.Next()))
    68     colCount++;
    70   return colCount;
    71 }
    73 uint32_t
    74 ARIAGridAccessible::RowCount()
    75 {
    76   uint32_t rowCount = 0;
    77   AccIterator rowIter(this, filters::GetRow);
    78   while (rowIter.Next())
    79     rowCount++;
    81   return rowCount;
    82 }
    84 Accessible*
    85 ARIAGridAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex)
    86 { 
    87   Accessible* row = GetRowAt(aRowIndex);
    88   if (!row)
    89     return nullptr;
    91   return GetCellInRowAt(row, aColumnIndex);
    92 }
    94 bool
    95 ARIAGridAccessible::IsColSelected(uint32_t aColIdx)
    96 {
    97   AccIterator rowIter(this, filters::GetRow);
    98   Accessible* row = rowIter.Next();
    99   if (!row)
   100     return false;
   102   do {
   103     if (!nsAccUtils::IsARIASelected(row)) {
   104       Accessible* cell = GetCellInRowAt(row, aColIdx);
   105       if (!cell || !nsAccUtils::IsARIASelected(cell))
   106         return false;
   107     }
   108   } while ((row = rowIter.Next()));
   110   return true;
   111 }
   113 bool
   114 ARIAGridAccessible::IsRowSelected(uint32_t aRowIdx)
   115 {
   116   Accessible* row = GetRowAt(aRowIdx);
   117   if(!row)
   118     return false;
   120   if (!nsAccUtils::IsARIASelected(row)) {
   121     AccIterator cellIter(row, filters::GetCell);
   122     Accessible* cell = nullptr;
   123     while ((cell = cellIter.Next())) {
   124       if (!nsAccUtils::IsARIASelected(cell))
   125         return false;
   126     }
   127   }
   129   return true;
   130 }
   132 bool
   133 ARIAGridAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx)
   134 {
   135   Accessible* row = GetRowAt(aRowIdx);
   136   if(!row)
   137     return false;
   139   if (!nsAccUtils::IsARIASelected(row)) {
   140     Accessible* cell = GetCellInRowAt(row, aColIdx);
   141     if (!cell || !nsAccUtils::IsARIASelected(cell))
   142       return false;
   143   }
   145   return true;
   146 }
   148 uint32_t
   149 ARIAGridAccessible::SelectedCellCount()
   150 {
   151   uint32_t count = 0, colCount = ColCount();
   153   AccIterator rowIter(this, filters::GetRow);
   154   Accessible* row = nullptr;
   156   while ((row = rowIter.Next())) {
   157     if (nsAccUtils::IsARIASelected(row)) {
   158       count += colCount;
   159       continue;
   160     }
   162     AccIterator cellIter(row, filters::GetCell);
   163     Accessible* cell = nullptr;
   165     while ((cell = cellIter.Next())) {
   166       if (nsAccUtils::IsARIASelected(cell))
   167         count++;
   168     }
   169   }
   171   return count;
   172 }
   174 uint32_t
   175 ARIAGridAccessible::SelectedColCount()
   176 {
   177   uint32_t colCount = ColCount();
   178   if (!colCount)
   179     return 0;
   181   AccIterator rowIter(this, filters::GetRow);
   182   Accessible* row = rowIter.Next();
   183   if (!row)
   184     return 0;
   186   nsTArray<bool> isColSelArray(colCount);
   187   isColSelArray.AppendElements(colCount);
   188   memset(isColSelArray.Elements(), true, colCount * sizeof(bool));
   190   uint32_t selColCount = colCount;
   191   do {
   192     if (nsAccUtils::IsARIASelected(row))
   193       continue;
   195     AccIterator cellIter(row, filters::GetCell);
   196     Accessible* cell = nullptr;
   197     for (uint32_t colIdx = 0;
   198          (cell = cellIter.Next()) && colIdx < colCount; colIdx++)
   199       if (isColSelArray[colIdx] && !nsAccUtils::IsARIASelected(cell)) {
   200         isColSelArray[colIdx] = false;
   201         selColCount--;
   202       }
   203   } while ((row = rowIter.Next()));
   205   return selColCount;
   206 }
   208 uint32_t
   209 ARIAGridAccessible::SelectedRowCount()
   210 {
   211   uint32_t count = 0;
   213   AccIterator rowIter(this, filters::GetRow);
   214   Accessible* row = nullptr;
   216   while ((row = rowIter.Next())) {
   217     if (nsAccUtils::IsARIASelected(row)) {
   218       count++;
   219       continue;
   220     }
   222     AccIterator cellIter(row, filters::GetCell);
   223     Accessible* cell = cellIter.Next();
   224     if (!cell)
   225       continue;
   227     bool isRowSelected = true;
   228     do {
   229       if (!nsAccUtils::IsARIASelected(cell)) {
   230         isRowSelected = false;
   231         break;
   232       }
   233     } while ((cell = cellIter.Next()));
   235     if (isRowSelected)
   236       count++;
   237   }
   239   return count;
   240 }
   242 void
   243 ARIAGridAccessible::SelectedCells(nsTArray<Accessible*>* aCells)
   244 {
   245   AccIterator rowIter(this, filters::GetRow);
   247   Accessible* row = nullptr;
   248   while ((row = rowIter.Next())) {
   249     AccIterator cellIter(row, filters::GetCell);
   250     Accessible* cell = nullptr;
   252     if (nsAccUtils::IsARIASelected(row)) {
   253       while ((cell = cellIter.Next()))
   254         aCells->AppendElement(cell);
   256       continue;
   257     }
   259     while ((cell = cellIter.Next())) {
   260       if (nsAccUtils::IsARIASelected(cell))
   261         aCells->AppendElement(cell);
   262     }
   263   }
   264 }
   266 void
   267 ARIAGridAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells)
   268 {
   269   uint32_t colCount = ColCount();
   271   AccIterator rowIter(this, filters::GetRow);
   272   Accessible* row = nullptr;
   273   for (uint32_t rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
   274     if (nsAccUtils::IsARIASelected(row)) {
   275       for (uint32_t colIdx = 0; colIdx < colCount; colIdx++)
   276         aCells->AppendElement(rowIdx * colCount + colIdx);
   278       continue;
   279     }
   281     AccIterator cellIter(row, filters::GetCell);
   282     Accessible* cell = nullptr;
   283     for (uint32_t colIdx = 0; (cell = cellIter.Next()); colIdx++) {
   284       if (nsAccUtils::IsARIASelected(cell))
   285         aCells->AppendElement(rowIdx * colCount + colIdx);
   286     }
   287   }
   288 }
   290 void
   291 ARIAGridAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols)
   292 {
   293   uint32_t colCount = ColCount();
   294   if (!colCount)
   295     return;
   297   AccIterator rowIter(this, filters::GetRow);
   298   Accessible* row = rowIter.Next();
   299   if (!row)
   300     return;
   302   nsTArray<bool> isColSelArray(colCount);
   303   isColSelArray.AppendElements(colCount);
   304   memset(isColSelArray.Elements(), true, colCount * sizeof(bool));
   306   do {
   307     if (nsAccUtils::IsARIASelected(row))
   308       continue;
   310     AccIterator cellIter(row, filters::GetCell);
   311     Accessible* cell = nullptr;
   312     for (uint32_t colIdx = 0;
   313          (cell = cellIter.Next()) && colIdx < colCount; colIdx++)
   314       if (isColSelArray[colIdx] && !nsAccUtils::IsARIASelected(cell)) {
   315         isColSelArray[colIdx] = false;
   316       }
   317   } while ((row = rowIter.Next()));
   319   for (uint32_t colIdx = 0; colIdx < colCount; colIdx++)
   320     if (isColSelArray[colIdx])
   321       aCols->AppendElement(colIdx);
   322 }
   324 void
   325 ARIAGridAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows)
   326 {
   327   AccIterator rowIter(this, filters::GetRow);
   328   Accessible* row = nullptr;
   329   for (uint32_t rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
   330     if (nsAccUtils::IsARIASelected(row)) {
   331       aRows->AppendElement(rowIdx);
   332       continue;
   333     }
   335     AccIterator cellIter(row, filters::GetCell);
   336     Accessible* cell = cellIter.Next();
   337     if (!cell)
   338       continue;
   340     bool isRowSelected = true;
   341     do {
   342       if (!nsAccUtils::IsARIASelected(cell)) {
   343         isRowSelected = false;
   344         break;
   345       }
   346     } while ((cell = cellIter.Next()));
   348     if (isRowSelected)
   349       aRows->AppendElement(rowIdx);
   350   }
   351 }
   353 void
   354 ARIAGridAccessible::SelectRow(uint32_t aRowIdx)
   355 {
   356   AccIterator rowIter(this, filters::GetRow);
   358   Accessible* row = nullptr;
   359   for (uint32_t rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
   360     DebugOnly<nsresult> rv = SetARIASelected(row, rowIdx == aRowIdx);
   361     NS_ASSERTION(NS_SUCCEEDED(rv), "SetARIASelected() Shouldn't fail!");
   362   }
   363 }
   365 void
   366 ARIAGridAccessible::SelectCol(uint32_t aColIdx)
   367 {
   368   AccIterator rowIter(this, filters::GetRow);
   370   Accessible* row = nullptr;
   371   while ((row = rowIter.Next())) {
   372     // Unselect all cells in the row.
   373     DebugOnly<nsresult> rv = SetARIASelected(row, false);
   374     NS_ASSERTION(NS_SUCCEEDED(rv), "SetARIASelected() Shouldn't fail!");
   376     // Select cell at the column index.
   377     Accessible* cell = GetCellInRowAt(row, aColIdx);
   378     if (cell)
   379       SetARIASelected(cell, true);
   380   }
   381 }
   383 void
   384 ARIAGridAccessible::UnselectRow(uint32_t aRowIdx)
   385 {
   386   Accessible* row = GetRowAt(aRowIdx);
   388   if (row)
   389     SetARIASelected(row, false);
   390 }
   392 void
   393 ARIAGridAccessible::UnselectCol(uint32_t aColIdx)
   394 {
   395   AccIterator rowIter(this, filters::GetRow);
   397   Accessible* row = nullptr;
   398   while ((row = rowIter.Next())) {
   399     Accessible* cell = GetCellInRowAt(row, aColIdx);
   400     if (cell)
   401       SetARIASelected(cell, false);
   402   }
   403 }
   405 ////////////////////////////////////////////////////////////////////////////////
   406 // Protected
   408 bool
   409 ARIAGridAccessible::IsValidRow(int32_t aRow)
   410 {
   411   if (aRow < 0)
   412     return false;
   414   int32_t rowCount = 0;
   415   GetRowCount(&rowCount);
   416   return aRow < rowCount;
   417 }
   419 bool
   420 ARIAGridAccessible::IsValidColumn(int32_t aColumn)
   421 {
   422   if (aColumn < 0)
   423     return false;
   425   int32_t colCount = 0;
   426   GetColumnCount(&colCount);
   427   return aColumn < colCount;
   428 }
   430 Accessible*
   431 ARIAGridAccessible::GetRowAt(int32_t aRow)
   432 {
   433   int32_t rowIdx = aRow;
   435   AccIterator rowIter(this, filters::GetRow);
   437   Accessible* row = rowIter.Next();
   438   while (rowIdx != 0 && (row = rowIter.Next()))
   439     rowIdx--;
   441   return row;
   442 }
   444 Accessible*
   445 ARIAGridAccessible::GetCellInRowAt(Accessible* aRow, int32_t aColumn)
   446 {
   447   int32_t colIdx = aColumn;
   449   AccIterator cellIter(aRow, filters::GetCell);
   450   Accessible* cell = cellIter.Next();
   451   while (colIdx != 0 && (cell = cellIter.Next()))
   452     colIdx--;
   454   return cell;
   455 }
   457 nsresult
   458 ARIAGridAccessible::SetARIASelected(Accessible* aAccessible,
   459                                     bool aIsSelected, bool aNotify)
   460 {
   461   nsIContent *content = aAccessible->GetContent();
   462   NS_ENSURE_STATE(content);
   464   nsresult rv = NS_OK;
   465   if (aIsSelected)
   466     rv = content->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
   467                           NS_LITERAL_STRING("true"), aNotify);
   468   else
   469     rv = content->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
   470                           NS_LITERAL_STRING("false"), aNotify);
   472   NS_ENSURE_SUCCESS(rv, rv);
   474   // No "smart" select/unselect for internal call.
   475   if (!aNotify)
   476     return NS_OK;
   478   // If row or cell accessible was selected then we're able to not bother about
   479   // selection of its cells or its row because our algorithm is row oriented,
   480   // i.e. we check selection on row firstly and then on cells.
   481   if (aIsSelected)
   482     return NS_OK;
   484   roles::Role role = aAccessible->Role();
   486   // If the given accessible is row that was unselected then remove
   487   // aria-selected from cell accessible.
   488   if (role == roles::ROW) {
   489     AccIterator cellIter(aAccessible, filters::GetCell);
   490     Accessible* cell = nullptr;
   492     while ((cell = cellIter.Next())) {
   493       rv = SetARIASelected(cell, false, false);
   494       NS_ENSURE_SUCCESS(rv, rv);
   495     }
   496     return NS_OK;
   497   }
   499   // If the given accessible is cell that was unselected and its row is selected
   500   // then remove aria-selected from row and put aria-selected on
   501   // siblings cells.
   502   if (role == roles::GRID_CELL || role == roles::ROWHEADER ||
   503       role == roles::COLUMNHEADER) {
   504     Accessible* row = aAccessible->Parent();
   506     if (row && row->Role() == roles::ROW &&
   507         nsAccUtils::IsARIASelected(row)) {
   508       rv = SetARIASelected(row, false, false);
   509       NS_ENSURE_SUCCESS(rv, rv);
   511       AccIterator cellIter(row, filters::GetCell);
   512       Accessible* cell = nullptr;
   513       while ((cell = cellIter.Next())) {
   514         if (cell != aAccessible) {
   515           rv = SetARIASelected(cell, true, false);
   516           NS_ENSURE_SUCCESS(rv, rv);
   517         }
   518       }
   519     }
   520   }
   522   return NS_OK;
   523 }
   525 ////////////////////////////////////////////////////////////////////////////////
   526 // ARIAGridCellAccessible
   527 ////////////////////////////////////////////////////////////////////////////////
   530 ////////////////////////////////////////////////////////////////////////////////
   531 // Constructor
   533 ARIAGridCellAccessible::
   534   ARIAGridCellAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   535   HyperTextAccessibleWrap(aContent, aDoc), xpcAccessibleTableCell(this)
   536 {
   537   mGenericTypes |= eTableCell;
   538 }
   540 ////////////////////////////////////////////////////////////////////////////////
   541 // nsISupports
   543 NS_IMPL_ISUPPORTS_INHERITED(ARIAGridCellAccessible,
   544                             HyperTextAccessible,
   545                             nsIAccessibleTableCell)
   547 ////////////////////////////////////////////////////////////////////////////////
   548 // nsIAccessibleTableCell
   550 TableAccessible*
   551 ARIAGridCellAccessible::Table() const
   552 {
   553   Accessible* table = TableFor(Row());
   554   return table ? table->AsTable() : nullptr;
   555 }
   557 uint32_t
   558 ARIAGridCellAccessible::ColIdx() const
   559 {
   560   Accessible* row = Row();
   561   if (!row)
   562     return 0;
   564   int32_t indexInRow = IndexInParent();
   565   uint32_t colIdx = 0;
   566   for (int32_t idx = 0; idx < indexInRow; idx++) {
   567     Accessible* cell = row->GetChildAt(idx);
   568     roles::Role role = cell->Role();
   569     if (role == roles::GRID_CELL || role == roles::ROWHEADER ||
   570         role == roles::COLUMNHEADER)
   571       colIdx++;
   572   }
   574   return colIdx;
   575 }
   577 uint32_t
   578 ARIAGridCellAccessible::RowIdx() const
   579 {
   580   return RowIndexFor(Row());
   581 }
   583 bool
   584 ARIAGridCellAccessible::Selected()
   585 {
   586   Accessible* row = Row();
   587   if (!row)
   588     return false;
   590   return nsAccUtils::IsARIASelected(row) || nsAccUtils::IsARIASelected(this);
   591 }
   593 ////////////////////////////////////////////////////////////////////////////////
   594 // Accessible
   596 void
   597 ARIAGridCellAccessible::ApplyARIAState(uint64_t* aState) const
   598 {
   599   HyperTextAccessibleWrap::ApplyARIAState(aState);
   601   // Return if the gridcell has aria-selected="true".
   602   if (*aState & states::SELECTED)
   603     return;
   605   // Check aria-selected="true" on the row.
   606   Accessible* row = Parent();
   607   if (!row || row->Role() != roles::ROW)
   608     return;
   610   nsIContent *rowContent = row->GetContent();
   611   if (nsAccUtils::HasDefinedARIAToken(rowContent,
   612                                       nsGkAtoms::aria_selected) &&
   613       !rowContent->AttrValueIs(kNameSpaceID_None,
   614                                nsGkAtoms::aria_selected,
   615                                nsGkAtoms::_false, eCaseMatters))
   616     *aState |= states::SELECTABLE | states::SELECTED;
   617 }
   619 already_AddRefed<nsIPersistentProperties>
   620 ARIAGridCellAccessible::NativeAttributes()
   621 {
   622   nsCOMPtr<nsIPersistentProperties> attributes =
   623     HyperTextAccessibleWrap::NativeAttributes();
   625   // Expose "table-cell-index" attribute.
   626   Accessible* thisRow = Row();
   627   if (!thisRow)
   628     return attributes.forget();
   630   int32_t colIdx = 0, colCount = 0;
   631   uint32_t childCount = thisRow->ChildCount();
   632   for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
   633     Accessible* child = thisRow->GetChildAt(childIdx);
   634     if (child == this)
   635       colIdx = colCount;
   637     roles::Role role = child->Role();
   638     if (role == roles::GRID_CELL || role == roles::ROWHEADER ||
   639         role == roles::COLUMNHEADER)
   640       colCount++;
   641   }
   643   int32_t rowIdx = RowIndexFor(thisRow);
   645   nsAutoString stringIdx;
   646   stringIdx.AppendInt(rowIdx * colCount + colIdx);
   647   nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx);
   649   return attributes.forget();
   650 }
   652 void
   653 ARIAGridCellAccessible::Shutdown()
   654 {
   655   mTableCell = nullptr;
   656   HyperTextAccessibleWrap::Shutdown();
   657 }

mercurial