void XULListCellAccessible::ColHeaderCells(nsTArray<Accessible*>* aCells) { TableAccessible* table = Table(); NS_ASSERTION(table, "cell not in a table!"); if (!table) return; // Get column header cell from XUL listhead. Accessible* list = nullptr; Accessible* tableAcc = table->AsAccessible(); uint32_t tableChildCount = tableAcc->ChildCount(); for (uint32_t childIdx = 0; childIdx < tableChildCount; childIdx++) { Accessible* child = tableAcc->GetChildAt(childIdx); if (child->Role() == roles::LIST) { list = child; break; } } if (list) { Accessible* headerCell = list->GetChildAt(ColIdx()); if (headerCell) { aCells->AppendElement(headerCell); return; } } // No column header cell from XUL markup, try to get it from ARIA markup. TableCellAccessible::ColHeaderCells(aCells); }
NS_IMETHODIMP ARIAGridCellAccessible::GetColumnIndex(int32_t* aColumnIndex) { NS_ENSURE_ARG_POINTER(aColumnIndex); *aColumnIndex = -1; if (IsDefunct()) return NS_ERROR_FAILURE; Accessible* row = Parent(); if (!row) return NS_OK; *aColumnIndex = 0; int32_t indexInRow = IndexInParent(); for (int32_t idx = 0; idx < indexInRow; idx++) { Accessible* cell = row->GetChildAt(idx); roles::Role role = cell->Role(); if (role == roles::GRID_CELL || role == roles::ROWHEADER || role == roles::COLUMNHEADER) (*aColumnIndex)++; } return NS_OK; }
NS_IMETHODIMP ARIAGridCellAccessible::GetRowIndex(int32_t* aRowIndex) { NS_ENSURE_ARG_POINTER(aRowIndex); *aRowIndex = -1; if (IsDefunct()) return NS_ERROR_FAILURE; Accessible* row = Parent(); if (!row) return NS_OK; Accessible* table = row->Parent(); if (!table) return NS_OK; *aRowIndex = 0; int32_t indexInTable = row->IndexInParent(); for (int32_t idx = 0; idx < indexInTable; idx++) { row = table->GetChildAt(idx); if (row->Role() == roles::ROW) (*aRowIndex)++; } return NS_OK; }
nsresult HTMLFileInputAccessible::HandleAccEvent(AccEvent* aEvent) { nsresult rv = HyperTextAccessibleWrap::HandleAccEvent(aEvent); NS_ENSURE_SUCCESS(rv, rv); // Redirect state change events for inherited states to child controls. Note, // unavailable state is not redirected. That's a standard for unavailable // state handling. AccStateChangeEvent* event = downcast_accEvent(aEvent); if (event && (event->GetState() == states::BUSY || event->GetState() == states::REQUIRED || event->GetState() == states::HASPOPUP || event->GetState() == states::INVALID)) { Accessible* button = GetChildAt(0); if (button && button->Role() == roles::PUSHBUTTON) { RefPtr<AccStateChangeEvent> childEvent = new AccStateChangeEvent(button, event->GetState(), event->IsStateEnabled(), event->FromUserInput()); nsEventShell::FireEvent(childEvent); } } return NS_OK; }
static AtkObject* getRowHeaderCB(AtkTable *aTable, gint aRowIdx) { AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable)); if (!accWrap) return nullptr; Accessible* cell = accWrap->AsTable()->CellAt(aRowIdx, 0); if (!cell) return nullptr; // If the cell at the first column is row header then assume it is row // header for all columns, if (cell->Role() == roles::ROWHEADER) return AccessibleWrap::GetAtkObject(cell); // otherwise get row header for the data cell at the first column. TableCellAccessible* tableCell = cell->AsTableCell(); if (!tableCell) return nullptr; nsAutoTArray<Accessible*, 10> headerCells; tableCell->RowHeaderCells(&headerCells); if (headerCells.IsEmpty()) return nullptr; return AccessibleWrap::GetAtkObject(headerCells[0]); }
void XULListboxAccessible::SelectedCells(nsTArray<Accessible*>* aCells) { nsCOMPtr<nsIDOMXULMultiSelectControlElement> control = do_QueryInterface(mContent); NS_ASSERTION(control, "Doesn't implement nsIDOMXULMultiSelectControlElement."); nsCOMPtr<nsIDOMNodeList> selectedItems; control->GetSelectedItems(getter_AddRefs(selectedItems)); if (!selectedItems) return; uint32_t selectedItemsCount = 0; DebugOnly<nsresult> rv = selectedItems->GetLength(&selectedItemsCount); NS_ASSERTION(NS_SUCCEEDED(rv), "GetLength() Shouldn't fail!"); for (uint32_t index = 0; index < selectedItemsCount; index++) { nsCOMPtr<nsIDOMNode> itemNode; selectedItems->Item(index, getter_AddRefs(itemNode)); nsCOMPtr<nsIContent> itemContent(do_QueryInterface(itemNode)); Accessible* item = mDoc->GetAccessible(itemContent); if (item) { uint32_t cellCount = item->ChildCount(); for (uint32_t cellIdx = 0; cellIdx < cellCount; cellIdx++) { Accessible* cell = mChildren[cellIdx]; if (cell->Role() == roles::CELL) aCells->AppendElement(cell); } } } }
Relation XULGroupboxAccessible::RelationByType(RelationType aType) { Relation rel = AccessibleWrap::RelationByType(aType); if (aType != RelationType::LABELLED_BY) return rel; // The label for xul:groupbox is generated from xul:label that is // inside the anonymous content of the xul:caption. // The xul:label has an accessible object but the xul:caption does not uint32_t childCount = ChildCount(); for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) { Accessible* childAcc = GetChildAt(childIdx); if (childAcc->Role() == roles::LABEL) { // Ensure that it's our label Relation reverseRel = childAcc->RelationByType(RelationType::LABEL_FOR); Accessible* testGroupbox = nullptr; while ((testGroupbox = reverseRel.Next())) if (testGroupbox == this) { // The <label> points back to this groupbox rel.AppendTarget(childAcc); } } } return rel; }
Relation HTMLLegendAccessible::RelationByType(RelationType aType) const { Relation rel = HyperTextAccessibleWrap::RelationByType(aType); if (aType != RelationType::LABEL_FOR) return rel; Accessible* groupbox = Parent(); if (groupbox && groupbox->Role() == roles::GROUPING) rel.AppendTarget(groupbox); return rel; }
void XULButtonAccessible::CacheChildren() { // In general XUL button has not accessible children. Nevertheless menu // buttons can have button (@type="menu-button") and popup accessibles // (@type="menu-button" or @type="menu"). // XXX: no children until the button is menu button. Probably it's not // totally correct but in general AT wants to have leaf buttons. bool isMenu = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, nsGkAtoms::menu, eCaseMatters); bool isMenuButton = isMenu ? false : mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, nsGkAtoms::menuButton, eCaseMatters); NS_ENSURE_TRUE(mDoc,); if (!isMenu && !isMenuButton) return; Accessible* menupopup = nsnull; Accessible* button = nsnull; nsAccTreeWalker walker(mDoc, mContent, true); Accessible* child = nsnull; while ((child = walker.NextChild())) { roles::Role role = child->Role(); if (role == roles::MENUPOPUP) { // Get an accessible for menupopup or panel elements. menupopup = child; } else if (isMenuButton && role == roles::PUSHBUTTON) { // Button type="menu-button" contains a real button. Get an accessible // for it. Ignore dropmarker button which is placed as a last child. button = child; break; } else { // Unbind rejected accessible from document. Document()->UnbindFromDocument(child); } } if (!menupopup) return; AppendChild(menupopup); if (button) AppendChild(button); }
NS_IMETHODIMP nsXULListCellAccessible::GetTable(nsIAccessibleTable **aTable) { NS_ENSURE_ARG_POINTER(aTable); *aTable = nsnull; if (IsDefunct()) return NS_ERROR_FAILURE; Accessible* thisRow = Parent(); if (!thisRow || thisRow->Role() != roles::ROW) return NS_OK; Accessible* table = thisRow->Parent(); if (!table || table->Role() != roles::TABLE) return NS_OK; CallQueryInterface(table, aTable); return NS_OK; }
Accessible* nsAccUtils::TableFor(Accessible* aRow) { if (aRow) { Accessible* table = aRow->Parent(); if (table) { roles::Role tableRole = table->Role(); if (tableRole == roles::GROUPING) { // if there's a rowgroup. table = table->Parent(); if (table) tableRole = table->Role(); } return (tableRole == roles::TABLE || tableRole == roles::TREE_TABLE || tableRole == roles::MATHML_TABLE) ? table : nullptr; } } return nullptr; }
Accessible* AccGroupInfo::FirstItemOf(Accessible* aContainer) { // ARIA tree can be arranged by ARIA groups case #1 (previous sibling of a // group is a parent) or by aria-level. a11y::role containerRole = aContainer->Role(); Accessible* item = aContainer->NextSibling(); if (item) { if (containerRole == roles::OUTLINEITEM && item->Role() == roles::GROUPING) item = item->FirstChild(); if (item) { AccGroupInfo* itemGroupInfo = item->GetGroupInfo(); if (itemGroupInfo && itemGroupInfo->ConceptualParent() == aContainer) return item; } } // ARIA list and tree can be arranged by ARIA groups case #2 (group is // a child of an item). item = aContainer->LastChild(); if (!item) return nullptr; if (item->Role() == roles::GROUPING && (containerRole == roles::LISTITEM || containerRole == roles::OUTLINEITEM)) { item = item->FirstChild(); if (item) { AccGroupInfo* itemGroupInfo = item->GetGroupInfo(); if (itemGroupInfo && itemGroupInfo->ConceptualParent() == aContainer) return item; } } // Otherwise, it can be a direct child if the container is a list or tree. item = aContainer->FirstChild(); if (ShouldReportRelations(item->Role(), containerRole)) return item; return nullptr; }
NS_IMETHODIMP ARIAGridCellAccessible::GetTable(nsIAccessibleTable** aTable) { NS_ENSURE_ARG_POINTER(aTable); *aTable = nullptr; Accessible* thisRow = Parent(); if (!thisRow || thisRow->Role() != roles::ROW) return NS_OK; Accessible* table = thisRow->Parent(); if (!table) return NS_OK; roles::Role tableRole = table->Role(); if (tableRole != roles::TABLE && tableRole != roles::TREE_TABLE) return NS_OK; CallQueryInterface(table, aTable); return NS_OK; }
TableAccessible* HTMLTableCellAccessible::Table() const { Accessible* parent = const_cast<HTMLTableCellAccessible*>(this); while ((parent = parent->Parent())) { roles::Role role = parent->Role(); if (role == roles::TABLE || role == roles::TREE_TABLE) return parent->AsTable(); } return nullptr; }
Relation HTMLLegendAccessible::RelationByType(uint32_t aType) { Relation rel = HyperTextAccessibleWrap::RelationByType(aType); if (aType != nsIAccessibleRelation::RELATION_LABEL_FOR) return rel; Accessible* groupbox = Parent(); if (groupbox && groupbox->Role() == roles::GROUPING) rel.AppendTarget(groupbox); return rel; }
NS_IMETHODIMP nsXULListboxAccessible::GetSelectedCells(nsIArray **aCells) { NS_ENSURE_ARG_POINTER(aCells); *aCells = nsnull; if (IsDefunct()) return NS_ERROR_FAILURE; nsresult rv = NS_OK; nsCOMPtr<nsIMutableArray> selCells = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIDOMXULMultiSelectControlElement> control = do_QueryInterface(mContent); NS_ASSERTION(control, "Doesn't implement nsIDOMXULMultiSelectControlElement."); nsCOMPtr<nsIDOMNodeList> selectedItems; control->GetSelectedItems(getter_AddRefs(selectedItems)); if (!selectedItems) return NS_OK; PRUint32 selectedItemsCount = 0; rv = selectedItems->GetLength(&selectedItemsCount); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(mDoc, NS_ERROR_FAILURE); PRUint32 index = 0; for (; index < selectedItemsCount; index++) { nsCOMPtr<nsIDOMNode> itemNode; selectedItems->Item(index, getter_AddRefs(itemNode)); nsCOMPtr<nsIContent> itemContent(do_QueryInterface(itemNode)); Accessible* item = mDoc->GetAccessible(itemContent); if (item) { PRUint32 cellCount = item->ChildCount(); for (PRUint32 cellIdx = 0; cellIdx < cellCount; cellIdx++) { Accessible* cell = mChildren[cellIdx]; if (cell->Role() == roles::CELL) selCells->AppendElement(static_cast<nsIAccessible*>(cell), false); } } } NS_ADDREF(*aCells = selCells); return NS_OK; }
already_AddRefed<nsIAccessibleTable> nsHTMLTableCellAccessible::GetTableAccessible() { Accessible* parent = this; while ((parent = parent->Parent())) { roles::Role role = parent->Role(); if (role == roles::TABLE || role == roles::TREE_TABLE) { nsIAccessibleTable* tableAcc = nsnull; CallQueryInterface(parent, &tableAcc); return tableAcc; } } return nsnull; }
Accessible* nsAccUtils::GetAncestorWithRole(Accessible* aDescendant, uint32_t aRole) { Accessible* document = aDescendant->Document(); Accessible* parent = aDescendant; while ((parent = parent->Parent())) { uint32_t testRole = parent->Role(); if (testRole == aRole) return parent; if (parent == document) break; } return nullptr; }
NS_IMETHODIMP nsXULListCellAccessible::GetColumnHeaderCells(nsIArray **aHeaderCells) { NS_ENSURE_ARG_POINTER(aHeaderCells); *aHeaderCells = nsnull; if (IsDefunct()) return NS_ERROR_FAILURE; nsCOMPtr<nsIAccessibleTable> table; GetTable(getter_AddRefs(table)); NS_ENSURE_STATE(table); // we expect to be in a listbox (table) // Get column header cell from XUL listhead. Accessible* list = nsnull; nsRefPtr<Accessible> tableAcc(do_QueryObject(table)); PRUint32 tableChildCount = tableAcc->ChildCount(); for (PRUint32 childIdx = 0; childIdx < tableChildCount; childIdx++) { Accessible* child = tableAcc->GetChildAt(childIdx); if (child->Role() == roles::LIST) { list = child; break; } } if (list) { PRInt32 colIdx = -1; GetColumnIndex(&colIdx); nsIAccessible *headerCell = list->GetChildAt(colIdx); if (headerCell) { nsresult rv = NS_OK; nsCOMPtr<nsIMutableArray> headerCells = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); headerCells->AppendElement(headerCell, false); NS_ADDREF(*aHeaderCells = headerCells); return NS_OK; } } // No column header cell from XUL markup, try to get it from ARIA markup. return nsAccUtils::GetHeaderCellsFor(table, this, nsAccUtils::eColumnHeaderCells, aHeaderCells); }
Accessible* nsAccUtils::GetSelectableContainer(Accessible* aAccessible, uint64_t aState) { if (!aAccessible) return nullptr; if (!(aState & states::SELECTABLE)) return nullptr; Accessible* parent = aAccessible; while ((parent = parent->Parent()) && !parent->IsSelect()) { if (parent->Role() == roles::PANE) return nullptr; } return parent; }
Relation XULLabelAccessible::RelationByType(uint32_t aType) { Relation rel = HyperTextAccessibleWrap::RelationByType(aType); if (aType == nsIAccessibleRelation::RELATION_LABEL_FOR) { // Caption is the label for groupbox nsIContent* parent = mContent->GetFlattenedTreeParent(); if (parent && parent->Tag() == nsGkAtoms::caption) { Accessible* parent = Parent(); if (parent && parent->Role() == roles::GROUPING) rel.AppendTarget(parent); } } return rel; }
Relation XULLabelAccessible::RelationByType(RelationType aType) { Relation rel = HyperTextAccessibleWrap::RelationByType(aType); if (aType == RelationType::LABEL_FOR) { // Caption is the label for groupbox nsIContent* parent = mContent->GetFlattenedTreeParent(); if (parent && parent->IsXULElement(nsGkAtoms::caption)) { Accessible* parent = Parent(); if (parent && parent->Role() == roles::GROUPING) rel.AppendTarget(parent); } } return rel; }
void ARIAGridCellAccessible::ApplyARIAState(uint64_t* aState) const { HyperTextAccessibleWrap::ApplyARIAState(aState); // Return if the gridcell has aria-selected="true". if (*aState & states::SELECTED) return; // Check aria-selected="true" on the row. Accessible* row = Parent(); if (!row || row->Role() != roles::ROW) return; nsIContent* rowContent = row->GetContent(); if (nsAccUtils::HasDefinedARIAToken(rowContent, nsGkAtoms::aria_selected) && !rowContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_selected, nsGkAtoms::_false, eCaseMatters)) *aState |= states::SELECTABLE | states::SELECTED; }
int32_t nsAccUtils::GetDefaultLevel(Accessible* aAccessible) { roles::Role role = aAccessible->Role(); if (role == roles::OUTLINEITEM) return 1; if (role == roles::ROW) { Accessible* parent = aAccessible->Parent(); // It is a row inside flatten treegrid. Group level is always 1 until it // is overriden by aria-level attribute. if (parent && parent->Role() == roles::TREE_TABLE) return 1; } return 0; }
void nsHTMLTableAccessible::CacheChildren() { // Move caption accessible so that it's the first child. Check for the first // caption only, because nsAccessibilityService ensures we don't create // accessibles for the other captions, since only the first is actually // visible. nsAccTreeWalker walker(mDoc, mContent, CanHaveAnonChildren()); Accessible* child = nsnull; while ((child = walker.NextChild())) { if (child->Role() == roles::CAPTION) { InsertChildAt(0, child); while ((child = walker.NextChild()) && AppendChild(child)); break; } AppendChild(child); } }
NS_IMETHODIMP ARIAGridCellAccessible::IsSelected(bool* aIsSelected) { NS_ENSURE_ARG_POINTER(aIsSelected); *aIsSelected = false; if (IsDefunct()) return NS_ERROR_FAILURE; Accessible* row = Parent(); if (!row || row->Role() != roles::ROW) return NS_OK; if (!nsAccUtils::IsARIASelected(row) && !nsAccUtils::IsARIASelected(this)) return NS_OK; *aIsSelected = true; return NS_OK; }
uint32_t XULListCellAccessible::ColIdx() const { Accessible* row = Parent(); if (!row) return 0; int32_t indexInRow = IndexInParent(); uint32_t colIdx = 0; for (int32_t idx = 0; idx < indexInRow; idx++) { Accessible* cell = row->GetChildAt(idx); roles::Role role = cell->Role(); if (role == roles::CELL || role == roles::GRID_CELL || role == roles::ROWHEADER || role == roles::COLUMNHEADER) colIdx++; } return colIdx; }
role XULListitemAccessible::NativeRole() { Accessible* list = GetListAccessible(); if (!list) { NS_ERROR("No list accessible for listitem accessible!"); return roles::NOTHING; } if (list->Role() == roles::TABLE) return roles::ROW; if (mIsCheckbox) return roles::CHECK_RICH_OPTION; if (mParent && mParent->Role() == roles::COMBOBOX_LIST) return roles::COMBOBOX_OPTION; return roles::RICH_OPTION; }
role XULMenupopupAccessible::NativeRole() { // If accessible is not bound to the tree (this happens while children are // cached) return general role. if (mParent) { roles::Role role = mParent->Role(); if (role == roles::COMBOBOX || role == roles::AUTOCOMPLETE) return roles::COMBOBOX_LIST; if (role == roles::PUSHBUTTON) { // Some widgets like the search bar have several popups, owned by buttons. Accessible* grandParent = mParent->Parent(); if (grandParent && grandParent->Role() == roles::AUTOCOMPLETE) return roles::COMBOBOX_LIST; } } return roles::MENUPOPUP; }
void XULColorPickerAccessible::CacheChildren() { NS_ENSURE_TRUE_VOID(mDoc); nsAccTreeWalker walker(mDoc, mContent, true); Accessible* child = nullptr; while ((child = walker.NextChild())) { uint32_t role = child->Role(); // Get an accessible for menupopup or panel elements. if (role == roles::ALERT) { AppendChild(child); return; } // Unbind rejected accessibles from the document. Document()->UnbindFromDocument(child); } }